Margines błędu może wynosić np 1 cm. Licząc w centymetrach stała powinna wynosić 1, licząc w metrach stała powinna wynosić 0.01. Dlatego wraz ze zmianą jednostki trzeba zmienić stałą EPSILON u ciebie, albo zastosować błąd względny i się tym nie martwić.
Double ma chyba 14 cyfr precyzji. Dlatego np mając dodatnie liczby x i y rzędu 10^14 ich różnica jest mniej więcej wielokrotnością jedynki. Przyjmując bezwzględny epsilon 0.000001 wymuszamy identyczność tych liczb.
java.lang.Math.ulp(liczba) podaje różnicę pomiędzy podaną, a następną reprezentowalną liczbą. Jeśli epsilon jest mniejszy od ulp to jest równoważy epsilonowi zerowemu.
Mając x i y tże x = 1 +- 1 oraz y = 1 +- 1 to x + 1014 == y + 1014 w doublach. Tego nie da się obejść. Dlatego w stabilnym numerycznie algorytmie powinno dodawać się liczby podobnego rzędu, natomiast nigdy nie powinno się odejmować bliskich liczb (co powoduje utratę cyfr znaczących).
Poza tym błąd względny jest najbardziej naturalnym rodzajem błędu. Jeśli porównujemy np wysokość człowieka, długość drogi do pracy czy szkoły, obwód bicepsa itd to generalnie przyjmujemy że wartości są równe jeżeli różnią się mniej niż np 1 %, a nie np 1 cm. Odchylenie 10 cm od pionu przy budowie wieżowca jest dużo mniej zauważalne niż przy budowie krzesła, gdyż jest dużo mniejsze względnie.
Kod:
package test;
public class Main {
static void print(double x) {
System.out.println("Liczba: " + x + ", ulp = " + Math.ulp(x));
}
public static void main(String[] args) {
print(1e-80);
print(1);
print(1e80);
}
}
Daje:
Liczba: 1.0E-80, ulp = 1.8726705418768793E-96
Liczba: 1.0, ulp = 2.220446049250313E-16
Liczba: 1.0E80, ulp = 1.3164036458569648E64
Jak można się było domyślić, ulp jest wprost proporcjonalny do wielkości liczby.