A menudo termino en situaciones en las que es necesario verificar si la diferencia obtenida está por encima de la precisión de la máquina. Parece que para este propósito R tiene una variable útil: .Machine$double.eps
. Sin embargo, cuando recurro al código fuente R para obtener pautas sobre el uso de este valor, veo múltiples patrones diferentes.
Ejemplos
Aquí hay algunos ejemplos de la 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.
Preguntas
- ¿Cómo entender el razonamiento detrás de todas esas diferentes
10 *
,100 *
,50 *
ysqrt()
modificadores? - ¿Existen pautas sobre el uso
.Machine$double.eps
para ajustar las diferencias debido a problemas de precisión?
r
floating-point
rounding
precision
Karolis Koncevičius
fuente
fuente
double.eps
. Si está realizando varias operaciones en un número de coma flotante, entonces su tolerancia a errores también debería ajustarse. Es por eso que all.equal te da unatolerance
discusión.Respuestas:
La precisión de la máquina
double
depende de su valor actual..Machine$double.eps
proporciona la precisión cuando los valores son 1. Puede usar la función CnextAfter
para obtener la precisión de la máquina para otros valores.Agregar valor
a
a valorb
no cambiaráb
cuandoa
sea la<=
mitad de la precisión de su máquina. Verificando si la diferencia es más pequeña que con la precisión de la máquina<
. Los modificadores podrían considerar casos típicos con qué frecuencia una adición no mostró un cambio.En R, la precisión de la máquina se puede estimar con:
Cada
double
valor representa un rango. Para una simple suma, el rango del resultado depende del reange de cada sumando y también del rango de su suma.Para mayor precisión se
Rmpfr
podría utilizar.En caso de que pudiera convertirse a entero,
gmp
podría usarse (lo que está en Rmpfr).fuente
Definición de una máquina.eps: es el valor más bajo
eps
para el que1+eps
no1
Como regla general (suponiendo una representación de punto flotante con base 2):
Esto
eps
hace la diferencia para el rango 1 .. 2,para el rango 2 .. 4 la precisión es
2*eps
y así sucesivamente.
Desafortunadamente, no hay una buena regla general aquí. Está completamente determinado por las necesidades de su programa.
En R tenemos all.equal como una forma integrada para probar la igualdad aproximada. Entonces podrías usar algo como
(x<y) | all.equal(x,y
)Google simulacro tiene una serie de comparadores de punto flotante para comparaciones de doble precisión, incluyendo
DoubleEq
yDoubleNear
. Puede usarlos en un comparador de matrices como este:Actualizar:
Las recetas numéricas proporcionan una derivación para demostrar que usar un cociente de diferencia unilateral
sqrt
es una buena opción de tamaño de paso para aproximaciones de derivadas de diferencias finitas.El sitio del artículo de Wikipedia Numerical Recipes, 3ra edición, Sección 5.7, que está en las páginas 229-230 (hay un número limitado de visitas a la página en http://www.nrbook.com/empanel/ ).
Esta aritmética de coma flotante IEEE es una limitación bien conocida de la aritmética informática y se discute en varios lugares:
.
dplyr::near()
es otra opción para probar si dos vectores de números de coma flotante son iguales.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
all.equal()
tiene su propia suposición como tolerancia predeterminadasqrt(double.eps)
: ¿por qué es la predeterminada? ¿Es una buena regla general usarsqrt()
?stats::
fuente R , y 2) cuáles son las pautas; La respuesta es bastante delgada. La única oración aplicable parece ser la referencia de "Recetas Numéricas" acerca de que sqrt () es un buen valor predeterminado, lo cual es realmente correcto, creo. O tal vez me estoy perdiendo algo aquí.