Сравнение чисел с плавающей запятой Python
Я просто просматриваю некоторые основы Python и есть сложная проблема сравнения чисел с плавающей запятой.
2.2 * 3.0 == 6.6
3.3 * 2.0 == 6.6
Я думал, что они оба вернут False. Однако второй дал мне Истину.
![enter image description here]()
Пожалуйста, помогите мне здесь. Спасибо!
Ответы
Ответ 1
Это может быть освещено:
>>> float.hex(2.2 * 3.0)
'0x1.a666666666667p+2'
>>> float.hex(3.3 * 2.0)
'0x1.a666666666666p+2'
>>> float.hex(6.6)
'0x1.a666666666666p+2'
Хотя все они отображаются в десятичном формате как 6.6
, когда вы проверяете внутреннее представление, два из них представлены одинаково, в то время как один из них не является.
Ответ 2
Чтобы закончить хороший ответ Амадана, вот более очевидный способ увидеть это 2.2 * 3. и 3.3 * 2. не представлены одним и тем же float: в оболочке Python
>>> 2.2 * 3.
6.6000000000000005
>>> 3.3 * 2.
6.6
На самом деле оболочка Python отображает представление чисел, которое по определению должно позволять правильному построению соответствующего поплавка из представления, поэтому вы видите численное приближение 2.2 * 3, которое делает Python. Тот факт, что 2.2 * 3.!= 3,3 * 2. очевидно, когда видны все необходимые цифры, например, выше.
Ответ 3
Также очевидно, что 3.3 * 2.0
по численности идентична 6.6
. Последнее вычисление является не чем иным, как увеличением двоичного показателя степени, поскольку оно является результатом умножения со степенью двойки. Вы можете увидеть это в следующем:
| s exponent significant
----+-------------------------------------------------------------------
1.1 | 0 01111111111 0001100110011001100110011001100110011001100110011010
2.2 | 0 10000000000 0001100110011001100110011001100110011001100110011010
3.3 | 0 10000000000 1010011001100110011001100110011001100110011001100110
6.6 | 0 10000000001 1010011001100110011001100110011001100110011001100110
Выше вы видите двоичное представление чисел с плавающей точкой 3.3
и 6.6
. Единственная разница в двух числах - это показатель степени, поскольку они умножаются только на два. Мы знаем, что IEEE-754 будет:
- приблизить десятичное число с наименьшей числовой ошибкой
- может представлять все целые числа до
2^53
точно (для двоичного 64)
Так как 2.0
точно представимо, умножение с этим числом будет не более чем изменением показателя степени. Таким образом, все последующее создаст одинаковые числа с плавающей точкой:
6.6 == 0.825 * 16.0 == 1.65 * 4.0 == 3.3*2.0 == 13.2 * 0.5 == ...
Означает ли это, что 2.2*3.0
отличается от 6.6
из-за значительного? Нет, это просто из-за ошибок округления при умножении.
Пример, где это работало бы, было бы 5.5*2.0 == 2.2*5.0 == 11.0
. Здесь округление было благоприятным