igualdade de ponto flutuante em Python e em geral
Eu tenho um pedaço de código que se comporta de maneira diferente, dependendo se eu passo por um dicionário para obter fatores de conversão ou se os uso diretamente.
O seguinte trecho de código será impresso1.0 == 1.0 -> False
Mas se você substituirfactors[units_from]
com10.0
efactors[units_to ]
com1.0 / 2.54
vai imprimir1.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
Deixe-me primeiro dizer que tenho certeza do que está acontecendo aqui. Eu já vi isso em C, nunca em Python, mas desde que o Python foi implementado em C, estamos vendo isso.
Eu sei que os números de ponto flutuante alterarão os valores que vão de um registro da CPU para o cache e vice-versa. Eu sei que comparar o que deveria ser duas variáveis iguais retornará false se uma delas foi paginada enquanto a outra permaneceu residente em um registro.
Questões
Qual é a melhor maneira de evitar problemas como este? ... Em Python ou em geral.Estou fazendo algo completamente errado?Nota
Obviamente, isso faz parte de um exemplo simplificado, mas o que estou tentando fazer é incluir classes de comprimento, volume etc. que podem ser comparadas com outros objetos da mesma classe, mas com unidades diferentes.
Perguntas retóricas
Se este for um problema potencialmente perigoso, pois faz com que os programas se comportem de maneira não-determinística, os compiladores devem avisar ou erro quando detectarem que você está verificando a igualdade de flutuaçõesOs compiladores devem suportar uma opção para substituir todas as verificações de igualdade de flutuação por uma função 'perto o suficiente'?Os compiladores já fazem isso e eu simplesmente não consigo encontrar as informações.