У меня есть фрагмент кода, который ведет себя по-разному в зависимости от того, просматриваю ли я словарь, чтобы получить коэффициенты преобразования или я использую их напрямую.
Следующий фрагмент кода напечатает 1.0 == 1.0 -> False
Но если вы замените factors[units_from]
на 10.0
и factors[units_to ]
на 1.0 / 2.54
, он напечатает 1.0 == 1.0 -> True
#!/usr/bin/env python
base = 'cm'
factors = {
'cm' : 1.0,
'mm' : 10.0,
'm' : 0.01,
'km' : 1.0e-5,
'in' : 1.0 / 2.54,
'ft' : 1.0 / 2.54 / 12.0,
'yd' : 1.0 / 2.54 / 12.0 / 3.0,
'mile' : 1.0 / 2.54 / 12.0 / 5280,
'lightyear' : 1.0 / 2.54 / 12.0 / 5280 / 5.87849981e12,
}
# convert 25.4 mm to inches
val = 25.4
units_from = 'mm'
units_to = 'in'
base_value = val / factors[units_from]
ret = base_value * factors[units_to ]
print ret, '==', 1.0, '->', ret == 1.0
Позвольте мне сначала сказать, что я уверен, что здесь происходит. Я видел это раньше в C, просто никогда на Python, но с Python в C реализовано в C. Мы видим это.
Я знаю, что числа с плавающей запятой изменят значения, поступающие из регистров CPU, в кеш и обратно. Я знаю, что сравнение двух равных переменных будет возвращать false, если один из них был выгружен, а другой остался резидентом в регистре.
Вопросы
- Каков наилучший способ избежать таких проблем?... В Python или вообще.
- Я делаю что-то совершенно неправильное?
Боковое примечание
Это, очевидно, часть урезанного примера, но то, что я пытаюсь сделать, связано с классами длины, тома и т.д., которые могут сравниваться с другими объектами одного и того же класса, но с разными единицами.
Риторические вопросы
- Если это потенциально опасная проблема, поскольку она заставляет программы работать в неопределенном вопросе, должны ли компиляторы предупреждать или ошибочно, когда обнаруживают, что вы проверяете равенство поплавков.
- Если компиляторы поддерживают возможность замены всех проверок равенства float с помощью функции "достаточно близко"?
- Компиляторы уже делают это, и я просто не могу найти информацию.