studio - superponer graficas en r
Dificultad numérica de comparación en R (6)
Estoy tratando de comparar dos números en R como parte de una condición de enunciado if:
(ab) >= 0.5
En este caso particular, a = 0.58 yb = 0.08 ... y aún (ab) >= 0.5
es falso. Soy consciente de los peligros de usar ==
para las comparaciones de números exactos, y esto parece estar relacionado:
(a - b) == 0.5)
es falso, mientras
all.equal((a - b), 0.5)
es verdadero.
La única solución que puedo pensar es tener dos condiciones: (ab) > 0.5 | all.equal((ab), 0.5)
(ab) > 0.5 | all.equal((ab), 0.5)
. Esto funciona, pero ¿es esa la única solución? ¿Debo jurar fuera de la =
familia de operadores de comparación para siempre?
Editar para mayor claridad: sé que este es un problema de punto flotante. Más fundamentalmente, lo que estoy preguntando es: ¿qué debo hacer al respecto? ¿Cuál es una forma sensata de tratar con comparaciones de mayor que o igual en R, ya que no se puede confiar en >=
?
Elija un nivel de tolerancia:
epsilon <- 1e-10
Entonces usa
(a-b+epsilon) >= 0.5
Nunca he sido un fan de todos. all.equal
por esas cosas. Me parece que la tolerancia funciona de manera misteriosa a veces. ¿Por qué no solo busca algo superior a una tolerancia inferior a 0.05?
tol = 1e-5
(a-b) >= (0.05-tol)
En general, sin redondeo y con la lógica convencional, la lógica directa es mejor que la de todos.
Si x == y
entonces xy == 0
. Quizás xy
no sea exactamente 0, así que para esos casos yo uso
abs(x-y) <= tol
all.equal
establecer la tolerancia de todos modos para all.equal
y esto es más compacto y directo que all.equal
.
Para mayor completitud, señalaré que, en ciertas situaciones, podría simplemente redondear a unas pocas cifras decimales (y esta es una solución poco convincente en comparación con la mejor solución publicada anteriormente).
round(0.58 - 0.08, 2) == 0.5
Pero, si usa tolerancias de todos modos, ¿por qué le preocupa que ab == .5 (de hecho) no se evalúe? Si está usando tolerancias de todos modos, está diciendo que no me importan exactamente los puntos finales.
Esto es lo que es verdadero si ((ab)> = .5) if ((ab) <.5)
uno de ellos siempre debe evaluar la verdad en cada par de dobles. Cualquier código que use uno implícitamente define una operación sin en la otra, al menos. Si el uso de tolerancias para obtener .5 real incluido en el primero, pero su problema se define en un dominio continuo que no está logrando mucho. En la mayoría de los problemas que involucran valores continuos en el problema subyacente, esto tendrá muy poco sentido, ya que los valores arbitrariamente superiores a .5 siempre evaluarán como deberían. Los valores arbitrariamente cercanos a .5 irán al control de flujo "incorrecto", pero en problemas continuos donde se usa la precisión adecuada que no importa.
El único momento en que las tolerancias tienen sentido es cuando se trata de problemas del tipo if ((ab) == c) if ((ab)! = C)
Aquí ninguna cantidad de "precisión apropiada" puede ayudarte. La razón es que tienes que estar preparado para que el segundo siempre se evalúe como verdadero a menos que establezcas los bits de ab en un nivel muy bajo a mano, cuando de hecho es probable que quieras que el primero sea a veces verdadero.
Puede crear esto como un operador separado o sobrescribir la función original> = (probablemente no sea una buena idea) si desea utilizar este enfoque con frecuencia:
# using a tolerance
epsilon <- 1e-10 # set this as a global setting
`%>=%` <- function(x, y) (x + epsilon > y)
# as a new operator with the original approach
`%>=%` <- function(x, y) (all.equal(x, y)==TRUE | (x > y))
# overwriting R''s version (not advised)
`>=` <- function(x, y) (isTRUE(all.equal(x, y)) | (x > y))
> (a-b) >= 0.5
[1] TRUE
> c(1,3,5) >= 2:4
[1] FALSE FALSE TRUE
Un comentario más. The all.equal
es un genérico. Para valores numéricos, usa all.equal.numeric
. Una inspección de esta función muestra que usó .Machine$double.eps^0.5
, donde .Machine$double.eps
se define como
double.eps: the smallest positive floating-point number ‘x’ such that
‘1 + x != 1’. It equals ‘double.base ^ ulp.digits’ if either
‘double.base’ is 2 or ‘double.rounding’ is 0; otherwise, it
is ‘(double.base ^ double.ulp.digits) / 2’. Normally
‘2.220446e-16’.
(Página de manual de Machine).
En otras palabras, esa sería una opción aceptable para su tolerancia:
myeq <- function(a, b, tol=.Machine$double.eps^0.5)
abs(a - b) <= tol