Problema de módulo de ponto flutuante
-
22-09-2019 - |
Pergunta
Eu tropecei em um bug muito estranho. Leia os comentários no código para ver o que é exatamente o bug, mas essencialmente um módulo 1 variável está retornando 1 (mas não é igual a 1!). Suponho que haja um problema de exibição em que o flutuador está extremamente próximo de um, mas não exatamente. No entanto, deve ser modular para zero. Não posso testar este caso facilmente porque (último % 1)! = 1,0! Quando tento conectar os mesmos números em outro terminal Python, tudo se comporta corretamente. O que está acontecendo?
def r(k,i,p):
first = i*p
last = first + p
steps = int((i+1)*p) - int(i*p)
if steps < 1:
return p
elif steps >= 1:
if k == 0:
return 1 - (first % 1)
elif k == steps:
if i == 189:
print last, 1, type(last), last % 1, last - int(last)
# Prints: 73.0 1 <type 'float'> 1.0 1.0
print last % 1 == 1 # Returns False
if last % 1 == 1.0:
return 0
return (last % 1)
else:
return 1
Solução
Bem -vindo ao IEEE754, Aproveite sua estadia.
Outras dicas
A impressão não mostra toda a precisão do número como armazenado, você pode usar repr()
fazer isso
>>> last=72.99999999999999
>>> print last, 1, type(last), last % 1, last - int(last)
73.0 1 <type 'float'> 1.0 1.0
>>> print last % 1 == 1
False
>>> print repr(last), 1, type(last), repr(last%1), repr(last - int(last))
72.999999999999986 1 <type 'float'> 0.99999999999998579 0.99999999999998579
>>>
Você deve usar o math.fmod (x, y). Aqui está um trecho de http://docs.python.org/library/math.html:
"Observe que a expressão de python x % y pode não retornar o mesmo resultado. A intenção do padrão C é que Fmod (x, y) seja exatamente (matematicamente; para infinita precisão) igual a x - n*y para algum número inteiro n de modo que o resultado tenha o mesmo sinal que x e magnitude menor que o ABS (Y). O X % y do Python retorna um resultado com o sinal de Y, e pode não ser exatamente computável para argumentos de flutuação. Por exemplo, FMOD (-1e -100, 1E100) é -1e-100, mas o resultado do -1e-100 % 1E100 do Python é 1E100-1E-100, que não pode ser representado exatamente como um flutuador, e Rodadas para o surpreendente 1E100. Por esse motivo, a função fmod () é geralmente preferida ao trabalhar com carros alegóricos, enquanto o X % Y do Python é preferido ao trabalhar com números inteiros ".
Você poderia tentar o Math.fmod função em vez de last % 1
, talvez seja mais adequado para o seu problema. Ou você pode reformular seu problema no espaço inteiro.
De qualquer forma, não é uma boa prática comparar valores de flutuação usando a igualdade ==
operador, devido a resultados imprecisos, mesmo de operações parecidas triviais como 0.1 + 0.2 == 0.3