Não é realmente específico para a implementação do Python, mas deve se aplicar a qualquer função float para string decimal.
Um número de ponto flutuante é essencialmente um número binário, mas em notação científica com um limite fixo de números significativos.
O inverso de qualquer número que possua um fator de número primo que não seja compartilhado com a base sempre resultará em uma representação de ponto pontual recorrente. Por exemplo, 1/7 tem um fator primo, 7, que não é compartilhado com 10 e, portanto, tem uma representação decimal recorrente, e o mesmo vale para 1/10 com os fatores primos 2 e 5, o último não sendo compartilhado com 2 ; isso significa que 0,1 não pode ser representado exatamente por um número finito de bits após o ponto.
Como 0.1 não tem representação exata, uma função que converte a aproximação em uma sequência de pontos decimais geralmente tentará aproximar certos valores para que eles não obtenham resultados não intuitivos como 0.1000000000004121.
Como o ponto flutuante está em notação científica, qualquer multiplicação por uma potência da base afeta apenas a parte expoente do número. Por exemplo, 1.231e + 2 * 100 = 1.231e + 4 para notação decimal e, da mesma forma, 1.00101010e11 * 100 = 1.00101010e101 em notação binária. Se eu multiplicar por uma não potência da base, os dígitos significativos também serão afetados. Por exemplo 1.2e1 * 3 = 3.6e1
Dependendo do algoritmo usado, ele pode tentar adivinhar decimais comuns com base apenas nos números significativos. Tanto 0,1 como 0,4 têm os mesmos números significativos em binário, porque seus flutuadores são essencialmente truncamentos de (8/5) (2 ^ -4) e (8/5) (2 ^ -6), respectivamente. Se o algoritmo identificar o padrão 8/5 sigfig como o decimal 1.6, ele funcionará em 0.1, 0.2, 0.4, 0.8, etc. Ele também poderá ter padrões mágicos sigfig para outras combinações, como o float 3 dividido pelo float 10 e outros padrões mágicos estatisticamente prováveis de serem formados pela divisão por 10.
No caso de 3 * 0,1, os últimos números significativos provavelmente serão diferentes da divisão de um flutuador 3 por flutuador 10, fazendo com que o algoritmo não reconheça o número mágico da constante 0,3, dependendo de sua tolerância à perda de precisão.
Editar:
https://docs.python.org/3.1/tutorial/floatingpoint.html
Curiosamente, existem muitos números decimais diferentes que compartilham a mesma fração binária aproximada mais próxima. Por exemplo, os números 0.1 e 0.10000000000000001 e 0.1000000000000000055511151231257827021181583404541015625 são todos aproximados por 360287970189696397/2 ** 55. Como todos esses valores decimais compartilham a mesma aproximação, qualquer um deles pode ser exibido enquanto ainda preserva a avaliação invariante (repr (x) ) == x.
Não há tolerância para a perda de precisão, se float x (0,3) não for exatamente igual a float y (0,1 * 3), então repr (x) não será exatamente igual a repr (y).