Frequentemente, acabo em situações em que é necessário verificar se a diferença obtida está acima da precisão da máquina. Parece que para esta finalidade R tem uma variável útil: .Machine$double.eps
. No entanto, quando recorro ao código-fonte R para obter orientações sobre o uso desse valor, vejo vários padrões diferentes.
Exemplos
Aqui estão alguns exemplos da stats
biblioteca:
t.test.R
if(stderr < 10 *.Machine$double.eps * abs(mx))
chisq.test.R
if(abs(sum(p)-1) > sqrt(.Machine$double.eps))
integrar.R
rel.tol < max(50*.Machine$double.eps, 0.5e-28)
lm.influence.R
e[abs(e) < 100 * .Machine$double.eps * median(abs(e))] <- 0
princomp.R
if (any(ev[neg] < - 9 * .Machine$double.eps * ev[1L]))
etc.
Questões
- Como se pode compreender o raciocínio por trás de todos esses diferentes
10 *
,100 *
,50 *
esqrt()
modificadores? - Existem diretrizes sobre como usar
.Machine$double.eps
para ajustar diferenças devido a problemas de precisão?
r
floating-point
rounding
precision
Karolis Koncevičius
fonte
fonte
double.eps
. Se você estiver executando várias operações em um número de ponto flutuante, sua tolerância a erros também deverá se ajustar. É por isso que all.equal oferece umtolerance
argumento.Respostas:
A precisão da máquina
double
depende de seu valor atual..Machine$double.eps
fornece a precisão quando os valores são 1. Você pode usar a função CnextAfter
para obter a precisão da máquina para outros valores.A adição de valor
a
a valorb
não será alteradab
quandoa
houver<=
metade da precisão da máquina. Verificando se a diferença é menor que a precisão da máquina<
. Os modificadores podem considerar casos típicos com que frequência uma adição não mostrou uma alteração.Em R, a precisão da máquina pode ser estimada com:
Cada
double
valor está representando um intervalo. Para uma adição simples, o intervalo do resultado depende da reorganização de cada somamand e também do intervalo da soma.Para maior precissão
Rmpfr
pode ser usado.Caso pudesse ser convertido em número inteiro,
gmp
poderia ser usado (o que está em Rmpfr).fonte
Definição de machine.eps: é o valor mais baixo
eps
para o qual1+eps
não é1
Como regra geral (assumindo uma representação de ponto flutuante com base 2):
Isso
eps
faz a diferença para o intervalo 1 .. 2,para o intervalo 2 .. 4 a precisão é
2*eps
e assim por diante.
Infelizmente, não existe uma boa regra geral aqui. É totalmente determinado pelas necessidades do seu programa.
Em R, temos all.equal como uma maneira integrada de testar a igualdade aproximada. Então você pode usar algo como
(x<y) | all.equal(x,y
)O mock do Google tem vários marcadores de ponto flutuante para comparações de precisão dupla, incluindo
DoubleEq
eDoubleNear
. Você pode usá-los em um combinador de matriz como este:Atualizar:
As Receitas Numéricas fornecem uma derivação para demonstrar que o uso de um quociente de diferença unilateral
sqrt
é uma boa opção de tamanho de etapa para aproximações de diferenças finitas de derivadas.O site de artigo da Wikipedia Numerical Recipes, 3ª edição, Seção 5.7, que é as páginas 229-230 (um número limitado de visualizações de página está disponível em http://www.nrbook.com/empanel/ ).
Essa aritmética de ponto flutuante IEEE é uma limitação bem conhecida da aritmética computacional e é discutida em vários locais:
.
dplyr::near()
é outra opção para testar se dois vetores de números de ponto flutuante são iguais.A função possui um parâmetro de tolerância embutido:
tol = .Machine$double.eps^0.5
que pode ser ajustado. O parâmetro padrão é o mesmo que o padrão paraall.equal()
.fonte
all.equal()
possui sua própria suposição como tolerância padrãosqrt(double.eps)
- por que é o padrão? É uma boa regra de ouro usarsqrt()
?stats::
fonte R e 2) quais são as diretrizes; a resposta é bastante fina. A única frase aplicável parece ser a referência de "Receitas Numéricas" sobre sqrt () ser um bom padrão, o que é realmente importante, eu acho. Ou talvez esteja faltando alguma coisa aqui.