Я знаю, что стандарты C и C ++ оставляют многие аспекты языка, определенные реализацией, просто потому, что если существует архитектура с другими характеристиками, было бы очень трудно или невозможно написать для нее стандартный соответствующий компилятор.
Я знаю, что 40 лет назад у любого компьютера была своя уникальная спецификация. Однако я не знаю ни одной архитектуры, используемой сегодня, где:
CHAR_BIT != 8
signed
это не дополнение к двум (я слышал, у Java были проблемы с этим).- Плавающая точка не соответствует IEEE 754 (Правка: я имел в виду «не в двоичном кодировании IEEE 754»).
Причина, по которой я спрашиваю, состоит в том, что я часто объясняю людям, что хорошо, что C ++ не требует никаких других низкоуровневых аспектов, таких как типы фиксированного размера † . Это хорошо, потому что в отличие от «других языков» он делает ваш код переносимым при правильном использовании (Edit: потому что он может быть перенесен на большее количество архитектур, не требуя эмуляции низкоуровневых аспектов машины, таких как, например, арифметика двух дополнений в архитектуре знак + величина) , Но мне плохо, что я сам не могу указать на какую-то конкретную архитектуру.
Таким образом, вопрос заключается в следующем: какие архитектуры обладают вышеуказанными свойствами?
† не uint*_t
являются обязательными.
источник
Ответы:
Взгляни на этот
Серверы Unisys ClearPath Dorado
предлагая обратную совместимость для людей, которые еще не перенесли все свое программное обеспечение Univac.
Ключевые моменты:
CHAR_BIT == 9
Не знаю, предлагают ли они компилятор C ++, но могли бы .
И теперь появилась ссылка на недавний выпуск их руководства по Си:
Справочное руководство по программированию компилятора Unisys C
Раздел 4.5 содержит таблицу типов данных с 9, 18, 36 и 72 битами.
источник
char*
иvoid*
должен быть того же размера, и достаточно большим, чтобы вместить любой другой указатель. Остальное до реализации.sizeof(int*) == 2
, но дальние указатели также имели 16-битный селектор, так чтоsizeof(void*) == 4
.sizeof(int*) != sizeof(char*)
здесь: оба 36 бит. Но селектор байтов вchar*
находится в старших разрядах и игнорируется вint*
. (Однако я использовал другие машины, где `sizeof (char *)> sizeof (int *).)void*
) всегда имели одинаковый размер. (Конечно, вы не можете преобразовать указатель на функциюvoid*
, поскольку онаvoid*
может быть меньше. Но в соответствии со стандартом, вы не можете сделать это и сегодня.)Ни одно из ваших предположений не относится к мэйнфреймам. Для начала, я не знаю мэйнфрейма, который использует IEEE 754: IBM использует базовую 16 с плавающей запятой, а оба мейнфрейма Unisys используют базовую 8. Машины Unisys немного особенные во многих других отношениях: Бо упомянул 2200 архитектура, но архитектура MPS еще более странная: 48-битные слова с тегами. (Является ли слово указателем или нет, зависит от бита в слове.) И числовые представления составлены таким образом, что нет реального различия между плавающей точкой и интегральной арифметикой: с плавающей точкой - основание 8; он не требует нормализации и, в отличие от любой другой плавающей запятой, которую я видел, ставит десятичную дробь справа от мантиссы, а не слева, и использует знаменательную величину для показателя степени (в дополнение к мантиссе). С результатами, что интегральное значение с плавающей запятой имеет (или может иметь) точно такое же битовое представление как целое число со знаком. И нет никаких арифметических инструкций с плавающей запятой: если показатели двух значений равны 0, инструкция выполняет интегральную арифметику, в противном случае она выполняет арифметику с плавающей запятой. (Продолжение философии тегирования в архитектуре.)
int
может занимать 48 бит, 8 из них должны быть 0, иначе значение не будет рассматриваться как целое число.источник
Полное соответствие IEEE 754 редко встречается в реализациях с плавающей запятой. И ослабление спецификации в этом отношении позволяет много оптимизаций.
Например, поддержка subnorm отличается между x87 и SSE.
Оптимизации, такие как объединение умножения и сложения, которые были отдельными в исходном коде, также немного изменяют результаты, но это хорошая оптимизация для некоторых архитектур.
Или на x86 строгое соответствие IEEE может потребовать установки определенных флагов или дополнительных передач между регистрами с плавающей запятой и обычной памятью, чтобы заставить его использовать указанный тип с плавающей запятой вместо своих внутренних 80-битных операций с плавающей запятой.
А некоторые платформы вообще не имеют аппаратного обеспечения и поэтому должны эмулировать их в программном обеспечении. И некоторые из требований IEEE 754 могут быть дорогостоящими для реализации в программном обеспечении. В частности, могут быть проблемы с правилами округления.
Мой вывод заключается в том, что вам не нужны экзотические архитектуры для того, чтобы попасть в ситуации, когда вы не всегда хотите гарантировать строгое соответствие IEEE. По этой причине было мало языков программирования, гарантирующих строгое соответствие IEEE.
источник
long double
мог бы быть полезным и долгоживущим типом, поскольку единственной реальной проблемой было то, что он плохо работаетprintf
. Тот факт, что расширенный double хранит ведущий 1, явно ускоряет вычисления в системах без FPU, а также устраняет необходимость в специальной обработке денормалов в любом контексте, кроме преобразований в / из других типов. Жаль, что С всеprintf
испортил.Я нашел эту ссылку, где перечислены некоторые системы, где
CHAR_BIT != 8
. Они включаютИ, конечно же, возникает вопрос о переполнении стека: на каких платформах есть что-то кроме 8-битного символа
Что касается систем, отличных от двух, есть интересное чтение на comp.lang.c ++. Moderated . Подводя итог: есть платформы, имеющие свое дополнение или знак и представление величины.
источник
CHAR_BIT=32
, и Texas Instruments DSP от TMS32F28xx имеетCHAR_BIT=16
. GCC 3.2 для PDP-10 имеетCHAR_BIT=9
. Я думаю, у S / 360 тоже может быть не 8-битный символ.CHAR_BITS
это частичный дубликат.Я уверен, что системы VAX все еще используются. Они не поддерживают IEEE с плавающей точкой; они используют свои собственные форматы. Alpha поддерживает форматы VAX и IEEE с плавающей точкой.
Векторные машины Cray, такие как T90, также имеют свой собственный формат с плавающей запятой, хотя в более новых системах Cray используется IEEE. (T90, который я использовал, был выведен из эксплуатации несколько лет назад; я не знаю, находятся ли еще в активном использовании.)
T90 также имел / имеет некоторые интересные представления для указателей и целых чисел. Собственный адрес может указывать только на 64-битное слово. Компиляторы C и C ++ имели CHAR_BIT == 8 (необходимо, потому что он запускал Unicos, разновидность Unix и должен был взаимодействовать с другими системами), но собственный адрес мог указывать только на 64-битное слово. Все операции , байты-уровень были синтезированы компилятором, и
void*
илиchar*
хранятся смещение байта в высоком порядке 3 бита слова. И я думаю, что некоторые целочисленные типы имели биты заполнения.Мэйнфреймы IBM являются еще одним примером.
С другой стороны, эти конкретные системы не обязательно должны исключать изменения в языковом стандарте. Cray не проявил особого интереса к обновлению своего компилятора C до C99; предположительно то же самое применимо к компилятору C ++. Возможно, было бы разумно ужесточить требования к размещенным реализациям, таким как требование CHAR_BIT == 8, с плавающей запятой формата IEEE, если не полная семантика, и дополнение 2 без дополнительных битов для целых чисел со знаком. Старые системы могли продолжать поддерживать более ранние языковые стандарты (C90 не умер, когда вышел C99), и требования могли быть более свободными для автономных реализаций (встроенных систем), таких как DSP.
С другой стороны, у будущих систем могут быть веские причины делать то, что сегодня считается экзотикой.
источник
unsigned
целочисленных типов будут основной болью, в то время как знаковая арифметика будет в порядке.CHAR_BITS
Согласно исходному коду gcc :
CHAR_BIT
это16
биты для 1750a , архитектуры dsp16xx .CHAR_BIT
это24
биты для архитектуры dsp56k .CHAR_BIT
это32
биты для архитектуры c4x .Вы можете легко найти больше, выполнив:
или
если
CHAR_TYPE_SIZE
правильно определено.Соответствие IEEE 754
Если целевая архитектура не поддерживает инструкции с плавающей запятой, gcc может генерировать программный резерв, который по умолчанию не соответствует стандарту. Более того, можно использовать специальные опции (например,
-funsafe-math-optimizations
ведьма также отключает сохранение знака для нулей).источник
До недавнего времени двоичное представление IEEE 754 было необычным для графических процессоров, см. Паранойя с плавающей запятой для графических процессоров .
РЕДАКТИРОВАТЬ: в комментариях был поднят вопрос, относится ли с плавающей запятой GPU к обычному компьютерному программированию, не связанному с графикой. Да, черт возьми! Самые высокопроизводительные вычисления, производимые сегодня, выполняются на графических процессорах; список включает AI, интеллектуальный анализ данных, нейронные сети, физическое моделирование, прогноз погоды и многое другое. Одна из ссылок в комментариях показывает почему: преимущество графических процессоров с плавающей запятой на порядок .
Я хотел бы добавить еще одну вещь, которая более актуальна для вопроса OP: что люди делали 10-15 лет назад, когда плавающая точка GPU не была IEEE, и когда не было таких API, как сегодняшние OpenCL или CUDA, для программирования GPU? Хотите верьте, хотите нет, но первые пионеры вычислений на GPU сумели программировать GPU без API, чтобы сделать это ! Я встретил одного из них в моей компании. Вот что он сделал: он кодировал данные, необходимые для вычисления, в виде изображения с пикселями, представляющими значения, над которыми он работал, а затем использовал OpenGL для выполнения необходимых операций (таких как «размытие по Гауссу» для представления свертки с нормальным распределением). и т. д.) и декодировал полученное изображение обратно в массив результатов. И это все же было быстрее, чем при использовании процессора!
Именно это побудило NVidia наконец-то сделать свои двоичные данные внутренними, совместимыми с IEEE и представить API, ориентированный на вычисления, а не на манипуляции с изображениями.
источник
int f(int n) { return n <= 1 ? 1 : n * f(n-1); }
в CUDA? Если нет, то графические процессоры не имеют отношения к этому вопросу (который касается комитетов C и C ++).