Erros de arredondamento no R

O primeiro capítulo do livro R Inferno se chama Falling into the Floating Point Trap (Caindo na Armadilha do Ponto Flutuante). Ele dá vários exemplos de como muitas vezes esperamos o resultado de uma operação matemática e ele não é o que esperávamos. Por exemplo, quanto é 3 - 2,9? Todo mundo sabe, inclusive o R, que é 0,1:

3 - 2.9
## [1] 0.1

Mas se todos sabem isso, porque temos um resultado falso ao fazermos um teste lógico?

(3 - 2.9) == 0.1
## [1] FALSE

Isso se deve ao fato de computadores utilizarem um sistema de numeração binário, o que os impedem de representarem exatamente alguns números. Por exemplo, veja como o R representa internamente (3 - 2.9) e 0.1:

print(3 - 2.9, digits = 22)
## [1] 0.1000000000000000888178
print(0.1, digits = 22)
## [1] 0.1000000000000000055511

Claramente são valores diferentes. Portanto, faz sentido que o teste lógico de igualdade resulte em falso. Felizmente, há um jeito simples de lidar com isso. A função all.equal testa a chamada “igualdade próxima”. Com isso, é possível estabelecer uma tolerância para as comparações. Se a diferença entre os valores estiver dentro do nível definido (que por padrão é próximo de 1.5e-8), então obtemos o resultado esperado.

all.equal(3 - 2.9, 0.1)
## [1] TRUE
all.equal(3 - 2.9, 0.1, tolerance = 1e-10)
## [1] TRUE
all.equal(3 - 2.9, 0.1, tolerance = 1e-20)
## [1] "Mean relative difference: 8.326673e-16"

Mas o R não é a única linguagem que sofre desse mal. Em fevereiro de 2022, virou notícia no Brasil o fato do Nubank não deixar transferir R$ 17,99 via Pix. E a razão para isso é a mesma do R: problemas com a representação de valores via ponto flutuante. Mas erros assim são muito mais perigosos em sistemas bancários do que nessa brincadeira que mostrei aqui.