Можно ли предположить, что с плавающей запятой представляется с использованием IEEE754 float в C?

Плавающая точка - это реализация, определенная в C. Таким образом, никаких гарантий нет.

Наш код должен быть переносимым, мы обсуждаем, целесообразно ли использовать IEEE754 поплавки в нашем протоколе. По соображениям производительности было бы неплохо, если бы нам не приходилось конвертировать назад и вперед между форматом фиксированной точки при отправке или получении данных.

Хотя я знаю, что между платформами и архитектурами могут быть различия относительно размера long или wchar_t. Но я не могу найти какой-либо конкретной информации о float и double.

То, что я нашел до сих пор, что порядок байтов может быть отменен на платформах с большим энтидом. Хотя существуют платформы без поддержки с плавающей запятой, где код, содержащий float и double, даже не связывается. В противном случае платформы, похоже, придерживаются единой и двойной точности IEEE754.

Итак, можно ли предположить, что плавающая точка находится в IEEE754, когда она доступна?

EDIT: в ответ на комментарий:

Каково ваше определение "безопасно"?

Безопасным я имею в виду, что битовая диаграмма на одной системе означает одно и то же на другой (после вращения байта, чтобы иметь дело с контентом).

Ответ 1

По существу, все архитектуры, используемые в настоящее время без использования перфокарт, включая встроенные архитектуры и экзотические архитектуры обработки сигналов, предлагают одну из двух систем с плавающей запятой:

  • IEEE-754.
  • IEEE-754 кроме бла. То есть они в основном реализуют 754, но дешевле некоторых из более дорогих и/или неудобных битов.

Наиболее распространенные дешёвые ауты:

  • Промывка денормалов до нуля. Это делает недействительными некоторые иногда полезные теоремы (в частности, теорема о том, что ab может быть точно представлена, если a и b находятся в пределах коэффициента 2), но на практике это, как правило, не будет проблемой.
  • Неспособность распознать inf и NaN как особые. Эти архитектуры не будут следовать правилам, относящимся к inf и NaN как операндам, и могут не насыщаться до inf, вместо этого получая числа, которые больше, чем FLT_MAX, которые обычно распознаются другими архитектурами как NaN.
  • Правильное округление деления и квадратного корня. Намного легче гарантировать, что результат находится в пределах 1-3 ульпов точного результата, чем в пределах 1/2 ульпов. Особенно распространенным случаем является деление, которое должно быть реализовано как взаимное + умножение, которое теряет один бит точности.
  • Меньше или нет охранных цифр. Это необычное удешевление, но означает, что другие операции могут быть отключены на 1-2 ульта.

BUUUUT... даже те, за исключением бла архитектуры, все еще используют представление чисел IEEE-754. Помимо проблем с порядком байтов, биты, описывающие число с float или double в архитектуре A, по существу гарантированно будут иметь то же значение в архитектуре B.

Так что, пока все, что вас волнует, это представление ценностей, у вас все в порядке. Если вы заботитесь о кроссплатформенной последовательности операций, вам может потребоваться выполнить дополнительную работу.

РЕДАКТИРОВАТЬ: Как Chux упоминает в комментариях, распространенным дополнительным источником несоответствия между платформами является использование расширенной точности, такой как 80-битное внутреннее представление x87. Что противоположность дешевого и (при правильном обращении) полностью соответствует как IEEE-754, так и стандарту C, но это также приведет к тому, что результаты будут различаться в разных архитектурах и даже в версиях компилятора и после явно незначительного и несвязанного кода изменения. Однако: конкретный исполняемый файл x86/x64 НЕ будет давать разные результаты на разных процессорах из-за повышенной точности.

Ответ 2

Существует макрос для проверки (с C99):

C11 §6.10.8.3 Макросы условных функций

__STDC_IEC_559__ Целочисленная константа 1, предназначенная для указания соответствия спецификациям в приложении F (IEC 60559 с плавающей точкой арифметики).

IEC 60559 (сокращение от ISO/IEC/IEEE 60559) является другим именем для IEEE-754.

Приложение F затем устанавливает сопоставление между плавающими типами C и типами IEEE-754:

Плавающие типы C соответствуют форматам IEC 60559 следующим образом:

  • Тип float соответствует единому формату IEC 60559.
  • Двойной тип соответствует двойному формату IEC 60559.
  • Длинный двойной тип соответствует расширенному формату IEC 60559, 357) иначе расширенный формат без стандарта IEC 60559, в то время как двойной формат IEC 60559.

Ответ 3

Я предлагаю вам более внимательно изучить свое определение портативного устройства.

Я бы также предложил, чтобы ваше определение "безопасное" было недостаточным. Даже если двоичное представление (допускающее утверждение) в порядке, операции с переменными могут вести себя по-разному. В конце концов, существует несколько приложений с плавающей точкой, которые не включают операции с переменными.

Если вы хотите поддерживать все архитектуры хостов, которые когда-либо были созданы, то при условии, что формат с плавающей запятой IEEE по своей сути является небезопасным. Вам придется иметь дело с системами, поддерживающими разные форматы, системами, которые не поддерживают с плавающей точкой вообще, системами, для которых у компиляторов есть переключатели для выбора поведения с плавающей запятой (с некоторыми формами поведения, связанными с форматами, отличными от IEEE), процессорами, которые имеют необязательный сопроцессор (так что поддержка с плавающей запятой зависит от того, установлен ли дополнительный чип, но в остальном варианты ЦП идентичны), системы, которые эмулируют операции с плавающей запятой в программном обеспечении (некоторые такие программные эмуляторы настраиваются во время выполнения) и системы с ошибкой или неполной реализацией с плавающей запятой (которые могут быть или не быть основаны на IEEE).

Если вы хотите ограничить себя оборудованием старинного стажа, то ваш риск ниже, но не равен нулю. Практически все процессоры этого винтажа поддерживают IEEE в той или иной форме. Однако вы по-прежнему (как и со старыми процессорами) должны рассмотреть, какие операции с плавающей запятой вы хотите поддерживать, и компромиссы, которые вы готовы принять, чтобы иметь их. Различные процессоры (или эмуляция программного обеспечения) имеют менее полную реализацию плавающей запятой, чем другие, а некоторые по умолчанию настроены на то, чтобы не поддерживать некоторые функции, поэтому необходимо изменить настройки, чтобы включить некоторые функции, которые могут повлиять на производительность или правильность ваших код.

Если вам нужно разделить значения с плавающей запятой между приложениями (которые могут быть на разных хостах с различными функциями, построенными с использованием разных компиляторов и т.д.), вам нужно будет определить протокол. Этот протокол может включать формат IEEE, но все ваши приложения должны будут иметь возможность обрабатывать преобразование между протоколом и их собственными представлениями.

Ответ 4

Почти все общие архитектуры теперь используют IEEE-754, это не требуется стандартом. Раньше существовали старые архитектуры, отличные от IEE-754, и некоторые из них все еще могут быть вокруг.

Если для обмена данными сети требуется только одно требование, я советую:

  • Если __STDC_IEC_559__ определен, используйте только порядок сети для байтов и предположим, что у вас есть стандартный IEE-754 для float и double.
  • Если __STDC_IEC_559__ не определен, используйте специальный формат обмена, который может быть IEE-754 - один единственный протокол или что-то еще - требуется указание протокола.

Ответ 5

Строго говоря, небезопасно предполагать поддержку с плавающей запятой; вообще говоря, подавляющее большинство платформ поддержат его. Известные исключения включают (теперь устаревшие) системы VMS, работающие на чипах Alpha.

Если у вас есть роскошь проверки времени выполнения, рассмотрите paranoia, инструмент проверки с плавающей запятой, написанный Уильям Кахан.

Изменить: похоже, что ваше приложение больше связано с бинарными форматами, так как они относятся к хранению и/или сериализации. Я бы предложил сузить область действия для выбора сторонней библиотеки, которая поддерживает это. Вы можете сделать хуже, чем Буферы протокола Google.

Ответ 6

Как и другие, упомянутый макрос __STDC_IEC_559__, но он не очень полезен, потому что он только устанавливает компиляторы, которые полностью реализуют соответствующее приложение в стандарте C. Существуют компиляторы, которые реализуют только подмножество, но все же имеют (в основном) полезную поддержку IEEE с плавающей запятой.

Если вас интересует только двоичное представление, вы должны написать тест функции, который проверяет битовые шаблоны некоторых плавающих чисел. Что-то вроде:

#include <stdint.h>
#include <stdio.h>

typedef union {
    double   d;
    uint64_t i;
} double_bits;

int main() {
    double_bits b;
    b.d = 2.5;
    if (b.i != UINT64_C(0x4004000000000000)) {
        fprintf(stderr, "Not an IEEE-754 double\n");
        return 1;
    }
    return 0;
}

Проверьте пару чисел с разными показателями, мантиссами и знаками, и вы должны быть в безопасности. Поскольку эти тесты не стоят дорого, вы можете даже запустить их один раз во время выполнения.