O código a seguir está obviamente errado. Qual é o problema?
i <- 0.1
i <- i + 0.05
i
## [1] 0.15
if(i==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
## i does not equal 0.15
r
floating-point
floating-accuracy
r-faq
dplanet
fonte
fonte
Respostas:
Razão geral (independente de idioma)
Como nem todos os números podem ser representados exatamente na aritmética de ponto flutuante IEEE (o padrão que quase todos os computadores usam para representar números decimais e fazer contas com eles), nem sempre você obtém o que esperava. Isso é especialmente verdadeiro porque alguns valores que são decimais simples e finitos (como 0,1 e 0,05) não são representados exatamente no computador e, portanto, os resultados da aritmética neles podem não fornecer um resultado idêntico a uma representação direta do " conhecida "resposta.
Essa é uma limitação bem conhecida da aritmética computacional e é discutida em vários locais:
Comparando Escalares
A solução padrão para isso
R
é não usar==
, mas sim aall.equal
função. Ou melhor, já queall.equal
fornece muitos detalhes sobre as diferenças, se houver algumaisTRUE(all.equal(...))
.rendimentos
Mais alguns exemplos de uso em
all.equal
vez de==
(o último exemplo deve mostrar que isso mostrará corretamente as diferenças).Mais detalhes, copiados diretamente de uma resposta para uma pergunta semelhante :
O problema que você encontrou é que o ponto flutuante não pode representar frações decimais exatamente na maioria dos casos, o que significa que você encontrará frequentemente que as correspondências exatas falham.
enquanto R fica um pouco quando você diz:
Você pode descobrir o que realmente pensa em decimal:
Você pode ver que esses números são diferentes, mas a representação é um pouco difícil. Se olharmos para eles em binário (bem, hexadecimal, que é equivalente), obtemos uma imagem mais clara:
Você pode ver que eles diferem por
2^-53
, o que é importante porque esse número é a menor diferença representável entre dois números cujo valor é próximo a 1, como é este.Podemos descobrir em qualquer computador qual é esse menor número representável olhando no campo da máquina de R :
Você pode usar esse fato para criar uma função 'quase igual' que verifique se a diferença está próxima do menor número representável no ponto flutuante. Na verdade isso já existe:
all.equal
.Portanto, a função all.equal está realmente verificando se a diferença entre os números é a raiz quadrada da menor diferença entre duas mantissas.
Esse algoritmo fica um pouco engraçado perto de números extremamente pequenos chamados denormals, mas você não precisa se preocupar com isso.
Comparando vetores
A discussão acima assumiu uma comparação de dois valores únicos. Em R, não existem escalares, apenas vetores e a vetorização implícita é uma força da linguagem. Para comparar o valor de vetores em termos de elementos, os princípios anteriores são válidos, mas a implementação é um pouco diferente.
==
é vetorizado (faz uma comparação elemento a elemento) enquantoall.equal
compara os vetores inteiros como uma única entidade.Usando os exemplos anteriores
==
não fornece o resultado "esperado" eall.equal
não executa em elementosEm vez disso, uma versão que passa pelos dois vetores deve ser usada
Se uma versão funcional disso for desejada, ela poderá ser escrita
que pode ser chamado apenas
Como alternativa, em vez de agrupar
all.equal
ainda mais chamadas de função, você pode apenas replicar os internos relevantesall.equal.numeric
e usar a vetorização implícita:Essa é a abordagem adotada
dplyr::near
, que se documenta comofonte
Adicionando ao comentário de Brian (que é o motivo), você pode passar por isso usando
all.equal
:De acordo com o aviso de Joshua, aqui está o código atualizado (Obrigado Joshua):
fonte
all.equal
não retornaFALSE
quando há diferenças; portanto, você precisa envolvê-loisTRUE
ao usá-lo em umaif
instruçãoIsso é hackish, mas rápido:
fonte
all.equal(... tolerance)
parâmetroall.equal(0.147, 0.15, tolerance=0.05)
é verdade.dplyr::near()
é uma opção para testar se dois vetores de números de ponto flutuante são iguais. Este é o exemplo dos documentos :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
Eu tive um problema parecido. Eu usei a seguinte solução.
saída de intervalos de corte desiguais com base nas opções (dígitos = 2):
saída de intervalos de corte iguais com base na função redonda:
fonte
Comparações generalizadas ("<=", "> =", "=") na aritmética de duplo precião:
Comparando a <= b:
Comparando a> = b:
Comparando a = b:
fonte