Często kończę w sytuacjach, w których konieczne jest sprawdzenie, czy uzyskana różnica jest wyższa niż precyzja maszyny. Wygląda na to, w tym celu R ma zmienną poręczny: .Machine$double.eps
. Jednak po przejściu do kodu źródłowego R w celu uzyskania wskazówek dotyczących korzystania z tej wartości widzę wiele różnych wzorców.
Przykłady
Oto kilka przykładów z stats
biblioteki:
t.test.R
if(stderr < 10 *.Machine$double.eps * abs(mx))
chisq.test.R
if(abs(sum(p)-1) > sqrt(.Machine$double.eps))
integrate.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]))
itp.
pytania
- Jak można zrozumieć uzasadnienie wszystkich tych różnych
10 *
,100 *
,50 *
orazsqrt()
modyfikatory? - Czy istnieją wytyczne dotyczące używania
.Machine$double.eps
do korygowania różnic z powodu problemów z precyzją?
r
floating-point
rounding
precision
Karolis Koncevičius
źródło
źródło
double.eps
. Jeśli wykonujesz kilka operacji na liczbie zmiennoprzecinkowej, twoja tolerancja błędu również powinna się dostosować. Dlatego all.equal daje citolerance
argument.Odpowiedzi:
Precyzja maszyny
double
zależy od jej aktualnej wartości..Machine$double.eps
daje precyzję, gdy wartości wynoszą 1. Możesz użyć funkcji C,nextAfter
aby uzyskać dokładność maszyny dla innych wartości.Dodanie wartości
a
do wartościb
nie zmieni się,b
gdya
będzie to<=
połowa jej precyzji maszyny. Dokonuje się sprawdzenia, czy różnica jest mniejsza niż precyzja maszyny<
. Modyfikatory mogą brać pod uwagę typowe przypadki, jak często dodatek nie pokazywał zmiany.W R precyzję maszyny można oszacować za pomocą:
Każda
double
wartość reprezentuje zakres. Dla prostego dodania, zakres wyniku zależy od zmiany każdego summanda, a także zakresu ich sumy.Dla wyższej precyzji
Rmpfr
można zastosować.W przypadku, gdy można go przekonwertować na liczbę całkowitą,
gmp
można użyć (co jest w Rmpfr).źródło
Definicja machine.eps: jest to najniższa wartość,
eps
dla której1+eps
nie jest1
Zasadniczo (przy założeniu reprezentacji zmiennoprzecinkowej z bazą 2):
To
eps
robi różnicę dla zakresu 1 .. 2,dla zakresu 2 .. 4 precyzja jest
2*eps
i tak dalej.
Niestety nie ma tutaj dobrej zasady. Jest to całkowicie zależne od potrzeb Twojego programu.
W R mamy all.equal jako wbudowany sposób testowania przybliżonej równości. Więc możesz użyć czegoś takiego
(x<y) | all.equal(x,y
)Google mock ma wiele dopasowań zmiennoprzecinkowych do porównań podwójnej precyzji, w tym
DoubleEq
iDoubleNear
. Możesz użyć ich w dopasowaniu tablic, takim jak to:Aktualizacja:
Przepisy numeryczne dostarczają pochodnych, aby wykazać, że zastosowanie jednostronnego ilorazu różnicy
sqrt
jest dobrym wyborem wielkości kroku dla przybliżeń różnic skończonych pochodnych.Witryna z artykułami Wikipedii Przepisy numeryczne, wydanie trzecie, sekcja 5.7, czyli strony 229–230 (ograniczona liczba odsłon jest dostępna pod adresem http://www.nrbook.com/empanel/ ).
Te arytmetyki zmiennoprzecinkowe IEEE są dobrze znanym ograniczeniem arytmetyki komputerowej i są omawiane w kilku miejscach:
.
dplyr::near()
jest kolejną opcją do testowania, czy dwa wektory liczb zmiennoprzecinkowych są równe.Funkcja ma wbudowany parametr tolerancji:
tol = .Machine$double.eps^0.5
który można regulować. Domyślny parametr jest taki sam jak domyślny dlaall.equal()
.źródło
all.equal()
Ma również własne założenie, że istnieje domyślna tolerancjasqrt(double.eps)
- dlaczego jest to domyślna? Czy warto stosować tę zasadęsqrt()
?stats::
źródle R , i 2) jakie są wytyczne; odpowiedź jest dość cienka. Jedynym stosownym zdaniem wydaje się być odniesienie z „Przepisów numerycznych” o tym, że sqrt () jest dobrym domyślnym, co jest naprawdę trafne, jak sądzę. A może coś mi brakuje.