0.1 float больше 0,1 double. Я ожидал, что это будет ложным
Пусть:
double d = 0.1;
float f = 0.1;
следует выражение
(f > d)
return true
или false
?
Эмпирически, ответ true
. Однако я ожидал, что это будет false
.
Поскольку 0.1
не может быть идеально представлен в двоичном формате, а double имеет от 15
до 16
десятичные цифры точности, а float имеет только 7
. Таким образом, оба они меньше 0.1
, а double ближе к 0.1
.
Мне нужно точное описание true
.
Ответы
Ответ 1
Я бы сказал, что ответ зависит от режима округления при преобразовании double
в float
. float
имеет 24 бинарных бита точности, а double
- 53. В двоичном выражении 0,1:
0.1₁₀ = 0.0001100110011001100110011001100110011001100110011…₂
^ ^ ^ ^
1 10 20 24
Итак, если мы округлимся на 24-й цифре, мы получим
0.1₁₀ ~ 0.000110011001100110011001101
что больше точного значения и более точного приближения на 53 цифры.
Ответ 2
Число 0,1 будет округлено до ближайшего числа с плавающей запятой с заданной точностью. Это приближение может быть либо больше, либо меньше 0,1, поэтому, не глядя на фактические значения, вы не можете предсказать, является ли приближение с одной точностью или двойной точностью.
Здесь значение двойной точности округляется до (с использованием интерпретатора Python):
>>> "%.55f" % 0.1
'0.1000000000000000055511151231257827021181583404541015625'
И здесь значение одиночной точности:
>>> "%.55f" % numpy.float32("0.1")
'0.1000000014901161193847656250000000000000000000000000000'
Итак, вы можете видеть, что приближение с одной точностью больше.
Ответ 3
Если вы конвертируете .1
в двоичный код, вы получаете:
0.000110011001100110011001100110011001100110011001100...
повторяется навсегда
Сопоставляя типы данных, вы получаете:
float(.1) = %.00011001100110011001101
^--- note rounding
double(.1) = %.0001100110011001100110011001100110011001100110011010
Преобразуйте это в базу 10:
float(.1) = .10000002384185791015625
double(.1) = .100000000000000088817841970012523233890533447265625
Это было взято из статьи, написанной Брюсом Доусоном. его можно найти здесь:
Дубли не являются плавающими, поэтому не сравнивайте их
Ответ 4
Я думаю, комментарий Эрика Липперта по этому вопросу на самом деле является самым ясным объяснением, поэтому я отвечу ему как ответ:
Предположим, вы вычисляете 1/9 в 3-значном десятичном и 6-значном десятичном значении. 0,111 0.111111, правильно?
Теперь предположим, что вы вычисляете 6/9. 0,667 > 0,6666667, правильно?
У вас не может быть этого, что 6/9 в трехзначном десятичном значении равно 0.666, потому что это не самый близкий 3-значный десятичный символ до 6/9!
Ответ 5
Поскольку он не может быть точно представлен, сравнение 1/10 в базе 2 похоже на сравнение 1/7 в базе 10.
1/7 = 0.142857142857... но сравнивая при разных базовых 10 точках (3 против 6 знаков после запятой), мы имеем 0.143 > 0.142857.
Ответ 6
Просто добавьте к другим ответам, говорящим о IEEE-754 и x86: проблема еще сложнее, чем кажется. Не существует "одного" представления 0,1 в IEEE-754 - их два. Было бы справедливо либо округление последней цифры вниз, либо вверх. Эта разница может и действительно возникает, поскольку x86 не использует 64-битные вычисления для своих внутренних вычислений с плавающей запятой; он фактически использует 80 бит! Это называется двойной расширенной точностью.
Таким образом, даже среди просто компиляторов x86 иногда бывает, что одно и то же число представлено двумя разными способами, потому что некоторые вычисляют его двоичное представление с 64-битами, в то время как другие используют 80.
На самом деле это может произойти даже с одним и тем же компилятором даже на одной машине!
#include <iostream>
#include <cmath>
void foo(double x, double y)
{
if (std::cos(x) != std::cos(y)) {
std::cout << "Huh?!?\n"; //← you might end up here when x == y!!
}
}
int main()
{
foo(1.0, 1.0);
return 0;
}
См. Почему cos(x) != cos(y)
, хотя x == y
? для получения дополнительной информации.
Ответ 7
Ранг double больше, чем для float в преобразованиях. Проводя логическое сравнение, f приводится к удвоению, и, возможно, реализация, которую вы используете, дает непоследовательные результаты. Если вы суффикс f, поэтому компилятор регистрирует его как float, тогда вы получаете 0.00, который является ложным в двойном типе. Непроверенные плавающие типы являются двойными.
#include <stdio.h>
#include <float.h>
int main()
{
double d = 0.1;
float f = 0.1f;
printf("%f\n", (f > d));
return 0;
}