A docstring para numpy.finfo
atualmente define o atributo eps
como:
O menor número positivo representável tal que 1,0 + eps! = 1,0. [...]
Essa definição não é correta, pelo menos no caso comum dos formatos binários IEEE 754. Por exemplo, com o formato binário64 IEEE 754 sob o modo usual de arredondamento round-tie-to-even, a definição declarada fornece um valor de 2**-53 + 2**-105
(aprox. 1.1102230246251568e-16
), que é um pouco mais da metade do valor correto de 2**-52
(aproximadamente 2.220446049250313e-16
).
In [36]: eps = 2**-53 + 2**-105
In [37]: eps
Out[37]: 1.1102230246251568e-16
In [38]: 1.0 + eps != 1.0
Out[38]: True
In [39]: 1.0 + np.nextafter(eps, -np.inf) != 1.0
Out[39]: False
In [40]: np.finfo(float).eps
Out[40]: 2.2204460492503131e-16
Algumas reformulações possíveis:
O menor número positivo como 1.0 + eps é representável.
Ou:
A diferença entre 1,0 e o menor float representável maior que 1,0.
Ou pode ser definido em termos de nextafter
como:
O valor de
np.nextafter(1.0, np.inf) - 1.0
.
Para comparação, a seção 5.2.4.2.2, parágrafo 11 do padrão C99 define as várias macros *_EPSILON
( DBL_EPSILON
, FLT_EPSILON
, ...) como:
a diferença entre 1 e o menor valor maior que 1 que é representável no tipo de ponto flutuante fornecido, b 1− p
A docstring para epsneg
está igualmente incorreta.
Ah, olhando para a fonte , vejo que eps
é realmente calculado como a menor _poder de 2_ tal que 1 + eps != eps
. Isso não é a mesma coisa que a diferença entre 1.0
e o próximo float representável acima de 1.0
, embora as duas coisas aconteçam coincidir para IEEE 754 e o arredondamento round-tie-to-even modo. Portanto, minhas reformulações sugeridas acima são inválidas. Talvez algo como:
A menor potência de 2, que 1.0 + eps é representável.
seria melhor? Tecnicamente, esse 2
deve ser substituído pelo radical de ponto flutuante, mas isso provavelmente é desnecessariamente pedante. O NumPy atualmente tem suporte para radix 10 ou radix 16 floats?
[À parte, prefiro muito mais a definição de epsilon no estilo C99, uma vez que envolve apenas o formato e não depende da semântica da adição de ponto flutuante Em particular, a definição C99 não depende do modo de arredondamento atualmente em vigor, enquanto a definição 1 + eps != 1
sim.]
Um ponteiro para np.spacing
e np.nextafter
na seção "Consulte também" também seria potencialmente útil.
Aqui estamos quase 4 anos depois e isso não foi corrigido. Não acho que https://github.com/numpy/numpy/pull/14618 será suficiente para encerrar este problema.
Para esclarecer o relatório de bug, a definição atual de eps na docstring está desviada por um fator de 2 do valor de eps retornado por np.finfo. (Os números que dou abaixo são para implementações com o padrão de ponto flutuante IEEE-754 de 64 bits).
np.finfo (1.0) .eps = 2 ** - 52 = 2,220446049250313e-16
No entanto, o docstring define eps como
"O menor número positivo representável tal que 1,0 + eps! = 1,0."
O valor real de eps que satisfaria a definição 1.0 + eps_min! = 1.0 é:
eps_min = 2 -53 + 2 -105 = 1,1102230246251568e-16
que é quase metade do valor presente de np.finfo (1.0) .eps. Provavelmente não queremos alterar o valor de np.finfo (1.0) .eps, para manter a compatibilidade com versões anteriores, mas a definição de docstring de eps precisa ser corrigida para corresponder ao que é calculado. O código-fonte para np.finfo (1.0) eps usa numpy.MachAr, e olhando a documentação lá, que permite outras bases além de 2, acho que a melhor definição de eps é uma das primeiras opções que @mdickinson sugeriu anteriormente. Eu também adicionaria um valor de exemplo à descrição:
"A diferença entre 1,0 e a menor flutuação representável maior que 1,0. (Para flutuações binárias de 64 bits no padrão IEEE-754, eps = 2 ** - 52 ≅ 2,22e-16.)"
A docstring para epsneg está igualmente incorreta.
Eu também tropecei nessa imprecisão. Isso deve ser consertado.
Para referência, o Matlab documenta seu eps
(que tem o mesmo valor) como: "a distância de 1,0 até o próximo número de precisão dupla maior, ou seja, 2 ^ -52."
A definição atual está incorreta e confusa devido a problemas de arredondamento. @gwhammett a definição proposta é correta e mais descritiva e incentiva um RP a encerrar este problema.
Comentários muito úteis
Aqui estamos quase 4 anos depois e isso não foi corrigido. Não acho que https://github.com/numpy/numpy/pull/14618 será suficiente para encerrar este problema.
Para esclarecer o relatório de bug, a definição atual de eps na docstring está desviada por um fator de 2 do valor de eps retornado por np.finfo. (Os números que dou abaixo são para implementações com o padrão de ponto flutuante IEEE-754 de 64 bits).
np.finfo (1.0) .eps = 2 ** - 52 = 2,220446049250313e-16
No entanto, o docstring define eps como
O valor real de eps que satisfaria a definição 1.0 + eps_min! = 1.0 é:
eps_min = 2 -53 + 2 -105 = 1,1102230246251568e-16
que é quase metade do valor presente de np.finfo (1.0) .eps. Provavelmente não queremos alterar o valor de np.finfo (1.0) .eps, para manter a compatibilidade com versões anteriores, mas a definição de docstring de eps precisa ser corrigida para corresponder ao que é calculado. O código-fonte para np.finfo (1.0) eps usa numpy.MachAr, e olhando a documentação lá, que permite outras bases além de 2, acho que a melhor definição de eps é uma das primeiras opções que @mdickinson sugeriu anteriormente. Eu também adicionaria um valor de exemplo à descrição:
A docstring para epsneg está igualmente incorreta.