#c #floating-accuracy #double-precision
#c #плавающая точность #двойная точность
Вопрос:
В C я использую следующий код для определения порядка величины ошибки из-за ограниченной точности float и double:
float n=1;
float dec = 1;
while(n!=(n-dec)) {
dec = dec/10;
}
cout << dec << endl;
(в двойном случае все, что я делаю, это обмениваю float на double в строке 1 и 2)
Теперь, когда я компилирую и запускаю это с помощью g в системе Unix, результаты
Float 10^-8
Double 10^-17
Однако, когда я компилирую и запускаю его с помощью MinGW в Windows 7, результаты
Float 10^-20
Double 10^-20
В чем причина этого?
Комментарии:
1. Что-то подсказывает мне, что MinGW хранит промежуточные
n!=(n-dec)
данные с 80-битной расширенной точностью.10^-20
примерно равен эпсилону 80-битного FP…
Ответ №1:
Я думаю, я сделаю свой комментарий ответом и расширю его. Это моя гипотеза, я могу ошибаться.
MinGW в Windows, вероятно, пытается сохранить точность, повышая промежуточные выражения до полной 80-битной точности x86.
Следовательно, обе части выражения n != (n-dec)
вычисляются с точностью до 64 бит (80-битный FP имеет 64-битную мантиссу).
2^-64 ~ 10^-20
Таким образом, числа имеют смысл.
Visual Studio также (по умолчанию) будет продвигать промежуточные элементы. Но только до двойной точности.
Комментарии:
1. Флаги оптимизации, используемые в GCC, вероятно, также изменят выходные данные, поскольку это изменит способ обработки чисел с плавающей запятой. Также обратите внимание, что здесь дело не только в компиляторе, но и в самом чипе и в том, какой режим с плавающей запятой он использует. Компиляторы могут также генерировать специальные команды усечения для с плавающей запятой. Много переменных, но да, ваш ответ по существу правильный.
2. @edA-qa морт-ора-у: Согласен. Я подумал об этом немного больше. Все, что нужно, это чтобы режим FP был с повышенной точностью. Код также достаточно мал, чтобы не пропускать регистры x87. Таким образом, округления в хранилище не произойдет.
Ответ №2:
Почему вы не проверяете размер float и double в обеих ОС?
Комментарии:
1. На W7 это будет float = 32bit, double = 64bit (с использованием
sizeof()
). Как мне связать это с моими выводами сверху?
Ответ №3:
Это просто показывает, что разные среды используют разные размеры для float и double.
Согласно спецификации C , double должен быть как минимум таким же большим, как float . Если вы хотите узнать, насколько велики типы в вашей системе, используйте sizeof
.
Похоже, что ваши тесты указывают на то, что g использует отдельные размеры для float и double (32 и 64 бита соответственно), в то время как MinGW32 в вашей системе Windows использует одинаковый размер для обоих. Обе версии соответствуют стандарту, и на поведение вообще нельзя полагаться.
Комментарии:
1. Смотрите мой комментарий к сообщению suresh ниже. Размеры, используемые в моей системе Windows для float и double, разные.
2. @Agentlien: в обеих системах
float
значение равно 4 байтам иdouble
равно 8 байтам. При отключенной оптимизации MinGW ведет себя точно так же, как Unix.