El siguiente código es obviamente incorrecto. ¿Cuál es el 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
fuente
fuente
Respuestas:
Razón general (agnóstico del lenguaje)
Como no todos los números se pueden representar exactamente en aritmética de coma flotante IEEE (el estándar que casi todas las computadoras usan para representar números decimales y hacer cálculos matemáticos con ellos), no siempre obtendrá lo que esperaba. Esto es especialmente cierto porque algunos valores que son decimales finitos simples (como 0.1 y 0.05) no están representados exactamente en la computadora y, por lo tanto, los resultados de la aritmética en ellos pueden no dar un resultado que sea idéntico a una representación directa de " conocida "respuesta.
Esta es una limitación bien conocida de la aritmética informática y se discute en varios lugares:
Comparación de escalares
La solución estándar para esto
R
es no usar==
, sino laall.equal
función. O mejor dicho, ya queall.equal
da un montón de detalles acerca de las diferencias, si las hay,isTRUE(all.equal(...))
.rendimientos
Algunos ejemplos más de uso en
all.equal
lugar de==
(se supone que el último ejemplo muestra que esto mostrará correctamente las diferencias).Algunos detalles más, copiados directamente de una respuesta a una pregunta similar :
El problema que ha encontrado es que el punto flotante no puede representar fracciones decimales exactamente en la mayoría de los casos, lo que significa que con frecuencia encontrará que las coincidencias exactas fallan.
mientras que R miente levemente cuando dices:
Puedes averiguar lo que realmente piensa en decimal:
Puede ver que estos números son diferentes, pero la representación es un poco difícil de manejar. Si los miramos en binario (bueno, hexadecimal, que es equivalente) obtenemos una imagen más clara:
Puede ver que difieren en
2^-53
, lo cual es importante porque este número es la diferencia representable más pequeña entre dos números cuyo valor es cercano a 1, como lo es.Podemos averiguar para cualquier computadora cuál es este número representable más pequeño mirando el campo de máquina de R :
Puede usar este hecho para crear una función 'casi igual' que verifique que la diferencia esté cerca del número representable más pequeño en coma flotante. De hecho esto ya existe:
all.equal
.Entonces, la función all.equal en realidad está verificando que la diferencia entre los números es la raíz cuadrada de la diferencia más pequeña entre dos mantisas.
Este algoritmo se vuelve un poco divertido cerca de números extremadamente pequeños llamados denormales, pero no necesita preocuparse por eso.
Comparación de vectores
La discusión anterior supuso una comparación de dos valores individuales. En R, no hay escalares, solo vectores y la vectorización implícita es una fortaleza del lenguaje. Para comparar el valor de los vectores por elementos, se mantienen los principios anteriores, pero la implementación es ligeramente diferente.
==
está vectorizado (hace una comparación por elementos) mientrasall.equal
compara los vectores completos como una sola entidad.Usando los ejemplos anteriores
==
no da el resultado "esperado" yall.equal
no realiza elementos sabiosMás bien, se debe usar una versión que recorra los dos vectores
Si se desea una versión funcional de esto, se puede escribir
que se puede llamar simplemente
Alternativamente, en lugar de incluir
all.equal
aún más llamadas a funciones, puede replicar las partes internas relevantesall.equal.numeric
y utilizar la vectorización implícita:Este es el enfoque adoptado por
dplyr::near
, que se documenta comofuente
Agregando al comentario de Brian (que es la razón) puedes superar esto usando en su
all.equal
lugar:La advertencia de Joshua aquí es el código actualizado (Gracias Joshua):
fuente
all.equal
no regresaFALSE
cuando hay diferencias, por lo que debe envolverloisTRUE
cuando lo usa en unaif
declaración.Esto es hack, pero rápido:
fuente
all.equal(... tolerance)
parámetro.all.equal(0.147, 0.15, tolerance=0.05)
es verdad.dplyr::near()
es una opción para probar si dos vectores de números de coma flotante son iguales. Este es el ejemplo de los documentos :La función tiene un parámetro de tolerancia incorporado:
tol = .Machine$double.eps^0.5
que se puede ajustar. El parámetro predeterminado es el mismo que el predeterminado paraall.equal()
.fuente
Tuve un problema similar. Usé la siguiente solución.
salida de intervalos de corte desiguales basados en opciones (dígitos = 2):
Salida de intervalos de corte iguales basados en la función de redondeo:
fuente
Comparaciones generalizadas ("<=", "> =", "=") en aritmética de doble preción:
Comparando a <= b:
Comparando a> = b:
Comparando a = b:
fuente