JAVA Błąd wartości liczby typu double

0

Witam mam pewien problem z błędną wartością typu double otóż :

for( double i=0; i<1 ; i+=0.1 )
{
System.out.println(i);

}

zamiast wypisać : 0.1
0.2
0.3
0.4
itp..
wypisuje :

                         0.1                      
                         0.2                      
                         0.30000000000000004      
                         0.4                      
                         0.5                      
                         0.6                      
                         0.7                      
                         0.7999999999999999       
                         0.8999999999999999       
                         0.9999999999999999 

Do obliczeń potrzebuje dokładnych wartości i nie wiem z czym ten błąd może być związany. Niby jest niewielka różnica w wartości ale np dla kroku i+=0.2 różnica jest już większa. Byłbym wdzięczny gdyby ktoś podpowiedział w czym tkwi problem

1

Liczby, które wyświetlasz mają nieskończone rozwinięcie dwójkowe, a komputer posługuje się skończoną ilością cyfr. Możesz napisać własną arytmetykę liczb lub skorzystać z klasy BigDecimal.

0

Dziękuje za odpowiedź. Ale mam kolejne pytanie czy Klasa BigDecimal udostępnia typ danych liczb rzeczywistych takich jak double tyle ze zaokrąglając wartość pozbywa się tego błędu ? . Jeśli nie czy mógłbyś mi polecić sposób którym mógłbym sobie po prostu zaokrąglić wartość np do 2 miejsc po przecinku i wtedy pozbył bym się problemu. Z góry dziękuje za odpowiedź.

2

Co nazywasz zaokrągleniem liczby? Zmianę jej wartości, czy wyświetlenie tylko dwóch cyfr po przecinku? Pierwsze jest niemożliwe (przy wykorzystaniu typu double), drugie jest bardzo proste. Np. wyświetlanie na konsoli:

double x = 0.1+0.1+0.1;
System.out.printtf("% 8.2f \n",x);
0

Tak miałem na myśli zmianę wartości liczby. Skoro do wyświetlania można zaokrąglić to rozumiem że wartość zaokrąglona wyświetlana jest typu String czy nie mógł bym potem tego String castować na Doubla i tym sposobem uzyskać zmianę wartości ? czyli z 3.0000000001 na 3.0

1

Powinno działać, wypróbuj.

double x = 0.1+0.1+0.1;
String s = String.format(new Locale("en"),"%4.2f",x);
x = Double.parseDouble(s);
0
for(int i = 0; i < 10 ; i++)
{
    System.out.println(i / 10.0);
}

//EDIT
lub

  public static final double EPSILON = 0.00000001;
  
  public static boolean FloatCompareLess(double a, double b)
  {
    return a < b - EPSILON;
  }

  public static void main (String[] args)
  {
    for(double i = 0.0; FloatCompareLess(i, 1.0); i += 0.1)
    {
      System.out.printf("% 8.1f \n", i);
    }
  }
0

Popatrz na taki kod i zastanów się dlaczego przy dowolnej precyzji w zakresie 1..15 cyfr dostajesz idealnie prawidłowe wyniki.

	int precyzja = 15; //cyfr
	for(double i = 0; i < 1; i += 0.1d)
	{
		System.out.printf("%." + precyzja + "f%n", i);
	}

Robienie konwersji zmiennej typu double do Stringa, a potem z powrotem jest właśnie robieniem dodatkowych błędów zaokrągleń ponieważ obliczenia na poziomie operacji binarnych są optymalizowane, aby uzyskać możliwie najdokładniejszy wynik. "Poprawianie wartości" wbrew pozorom psuje niektóre optymalizacje i przy okazji wydajność. Popatrz na to:

	final double x = 0.1;
	final double zero = x + x + 6 * x - x - x - x - 5 * x;
	System.out.println("Maksymalna dokładność = " + zero);
	System.out.printf("Dokładność: duża = %.15f, przesadzona = %1$.20f%n", zero);

Wyniki:

0,000000000000000
0,100000000000000
0,200000000000000
0,300000000000000
0,400000000000000
0,500000000000000
0,600000000000000
0,700000000000000
0,800000000000000
0,900000000000000
1,000000000000000

Maksymalna dokładność = 1.1102230246251565E-16
Dokładność: duża = 0,000000000000000, przesadzona = 0,00000000000000011102

Epsilon może być przy niewielu obliczeniach podwójnej precyzji spokojnie ustalony na 1e-15, przy dłuższych obliczeniach można zejść do np. 1e-12.

0

zamień:

for( double i=0; i<1 ; i+=0.1 )
{
        System.out.println(i);

}

na

for(int i=0; i<10 ; i++ )
{
        System.out.println(i / 10.);

}

a tak ogólnie to jest dział matematyki http://wazniak.mimuw.edu.pl/index.php?title=Metody_numeryczne zajmujący się tworzeniem algorytmów działających dobrze na liczbach skończonej precyzji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1