Strona 1 z 1

[solved] Python - niezrozumiałe działanie porównania zmiennych

: 12 mar 2011, 17:08
autor: outslider
Witam!

Problem jest z kodem tak banalnym, że nie wiem, jak to może nie działać... kod:

Kod: Zaznacz cały

YMIN=-2.0
YMAX=2.0
d=30
y=YMIN
while y <= YMAX:
    print y
    y=y+(YMAX-YMIN)/(d-1)
wynik jest taki:

Kod: Zaznacz cały

-2.0
-1.86206896552
-1.72413793103
-1.58620689655
-1.44827586207
-1.31034482759
-1.1724137931
-1.03448275862
-0.896551724138
-0.758620689655
-0.620689655172
-0.48275862069
-0.344827586207
-0.206896551724
-0.0689655172414
0.0689655172414
0.206896551724
0.344827586207
0.48275862069
0.620689655172
0.758620689655
0.896551724138
1.03448275862
1.1724137931
1.31034482759
1.44827586207
1.58620689655
1.72413793103
1.86206896552
mimo iż spodziewam się raczej:

Kod: Zaznacz cały

-2.0
-1.86206896552
-1.72413793103
-1.58620689655
-1.44827586207
-1.31034482759
-1.1724137931
-1.03448275862
-0.896551724138
-0.758620689655
-0.620689655172
-0.48275862069
-0.344827586207
-0.206896551724
-0.0689655172414
0.0689655172414
0.206896551724
0.344827586207
0.48275862069
0.620689655172
0.758620689655
0.896551724138
1.03448275862
1.1724137931
1.31034482759
1.44827586207
1.58620689655
1.72413793103
1.86206896552
2.0
czyli z wartością "2.0" na końcu...

Kiedy zmienię kod na:

Kod: Zaznacz cały

YMIN=-2.0
YMAX=2.0
d=30
y=YMIN
while y <= YMAX+0.0000000001:
    print y
    y=y+(YMAX-YMIN)/(d-1)
to jakimś cudem otrzymuję to "2.0" na końcu. I to nie "2.0000000001" tylko właśnie "2.0". Kiedy zmienię d=30 na d=31 albo d=29 albo praktycznie na cokolwiek, to już działa, a dla 30 czy 60 nie. Dla d=3 też działa. Czy jest to jakaś kwestia przybliżeń? Czy co...

Nie mogę zastosować tego +0.0000000001 ponieważ wartości YMIN i YMAX oraz d mogą być bardzo zmienne i może się okazać, że są wręcz porównywalne z 0.0000000001 a wtedy kod się też będzie sypać...

Generalnie ciężka bania...

Odp: Python - niezrozumiałe działanie porównania zmiennych

: 12 mar 2011, 17:21
autor: karmelek
Faktycznie - może to być kwestia przybliżeń. Przynajmniej u mnie przy podobnych problemach winny okazywał się sposób reprezentacji liczb w komputerze.

Odp: Python - niezrozumiałe działanie porównania zmiennych

: 12 mar 2011, 17:29
autor: outslider
To kiepsko... Masz jakąś metodę, żeby to obejść?

Odp: Python - niezrozumiałe działanie porównania zmiennych

: 12 mar 2011, 18:18
autor: VGT
Na początek: kod niestety w innym języku, ale nie koduję w Pythonie, więc nie chciałem w ciemno pisać, bo mogłoby wyjść gorzej ;) Mam nadzieje, że kod z Javy będzie na tyle przejrzysty, że wyjaśni koncepcję:

Kod: Zaznacz cały

		float yMin = -2.0f;
		float yMax = 2.0f;
		float yStartValue = yMin;
		int d= 30;
		float y = yStartValue;
		int step = 0;
		while (y <= yMax)
			{
			++step;
			System.out.println(y);
			y = yStartValue + step * ((yMax - yMin) / (d - 1));
			}
Zastosowane tu jest coś podobnego, co powszechnie jest stosowane w transformacjach geometrii w grafice 3D. Jeśli miałeś kiedyś okazję coś takiego pisać, gdybyś próbował w każdej kolejnej klatce np obracać jakiś model 3D, z czasem zaczyna on być zniekształcony właśnie z powodu zaokrągleń. Rozwiązanie, to trzymać współrzędne modelu cały czas w bazowej formie, a w każdej kolejnej klatce nadawać mu coraz większy obrót, jednak nie nadpisywać tym bazowego modelu, a użyć jedynie do jego wyświetlenia.

Tak samo tutaj. W pętli za każdym razem do y przypisuję jego wartość początkową (co prawda tutaj akurat jest to yMin, ale zawsze wolę mieć osobną zmienną przechowującą wartość startową dla przejrzystości, stąd utworzenie yStartValue) powiększoną o ilość iteracji (wartość step) zmian, które chce do y dodać.

W Javie po takiej modyfikacji udało się 2.0 uzyskać. Jednak tak czy inaczej w przypadku zmiennych float/double ryzykowne jest oczekiwanie, że dwie wartości będą sobie równe właśnie ze względu na zaokrąglenia.

Odp: Python - niezrozumiałe działanie porównania zmiennych

: 12 mar 2011, 20:18
autor: outslider
@VGT
Dzięki! Działa!
W ogóle dopiero jak implementowałem Twój algorytm zauważyłem, że przecież ja robię tyle przebiegów co d+1 czyli mogę inkrementować spokojnie zmienną step dla step<=d :D Wtedy w ogóle nie ma problemu przybliżeń.

Pozdrawiam!