Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [PHP] IF, less or equal, nie działa :/
Tryllion
post
Post #1





Grupa: Zarejestrowani
Postów: 15
Pomógł: 0
Dołączył: 29.07.2009

Ostrzeżenie: (0%)
-----


Witam

Mam taki kod i nie rozumiem co może być źle, jak znaleźć error (IMG:style_emoticons/default/sciana.gif)

  1. IF( $val == $row->v ) {
  2. echo ' TAK';
  3. continue;
  4. }
  5. echo 'NIE'; continue;

ten if jest wywoływany w pętli while, nie rozumiem dlaczego ale czasem liczby o przecinkowej precyzji wcale nie są wykrywane jako równe (IMG:style_emoticons/default/exclamation.gif) !
Co może być tego przyczyną ? Czy to nie są wartości typu int tylko String np. jak to sprawdzić, co może być źle ?

proszę o wskazówki bo naprawdę nie rozumiem
Go to the top of the page
+Quote Post
InosU31
post
Post #2





Grupa: Zarejestrowani
Postów: 221
Pomógł: 14
Dołączył: 11.03.2009
Skąd: Lubaczów

Ostrzeżenie: (0%)
-----


do sprawdzenia jakiego typu jesli liczba badz jakas zmienna - bo chyba chcesz to sprawdzic - sluszy polecenie:

var_dump($zmienna);

a co do Twojego warunku to sprobuj tak :

  1. if( $val == $row->v ) {
  2. echo ' TAK';
  3.  
  4. }
  5. else echo 'NIE';


Pozdrawiam
Go to the top of the page
+Quote Post
thek
post
Post #3





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




O błędzie w składni if-else nie piszę bo to już wytknięto. Co do liczb zmiennoprzecinkowych to niestety z porównywaniem ich trzeba mocno uważać. O ile nie są to jakieś, nazwijmy to, proste w stylu 0.5 czy mające ciut więcej miejsc po przecinku, to już porównywanie wyników bardziej skomplikowanych wyrażeń może dawać nierówne wartości z racji określonej dokładności liczb, a w związku z tym przy działaniach zachodzą co i rusz zaokrąglenia. Im ich więcej, tym większa szansa, że porównanie zakończy się jako FALSE. Dobrym przykładem by to zobrazować może być popularne:
1/9 * 9
Jak wiadomo 1/9 daje w zapisie dziesiętnym 0.11111111111111111111111111
przemnożenie przez 9 da więc:
0.9999999999999999999
a nie jak nakazuje matematyka 1 i takie właśnie pułapki czekają na programistów co i rusz w związku z zaokrągleniami i przybliżeniami.

EDIT: To co podałem jest proste i kompy takie trywialne przypadki zazwyczaj wyłapują, więc 1 ostatecznie wychodzi, chociaż wynika to z przekształceń wyrażeń arytmetycznych na niskim poziomie. Dzielenie jest zamieniane zazwyczaj na mnożenie przez odwrotność (ale to też zależy od choćby obecności koprocesora), ale o tym możesz nie wiedzieć, bo nie każdy programista musi znać architekturę komputerową włącznie z budową procesora i operacjami prze niego wykonywanymi (IMG:style_emoticons/default/smile.gif) To miał być tylko przykład ilustrujący ideę, która leży u podstaw opisanego przez Ciebie błędu.

Ten post edytował thek 28.10.2009, 21:09:09
Go to the top of the page
+Quote Post
pheter
post
Post #4





Grupa: Zarejestrowani
Postów: 8
Pomógł: 1
Dołączył: 12.10.2009

Ostrzeżenie: (0%)
-----


@Tryllion, bardzo słusznie zauważyłeś, że liczby zmiennoprzecinkowe nie są wykrywane jako równe, mimo iż liczby rzeczywiste które reprezentują są równe. Dokładnie to liczby zmiennoprzecinkowe w postaci binarnej stanowią reprezentację liczb rzeczywistych z pewną dokładnością. Nie znam dokładnie php i nie wiem czy są w tym języku jakieś specjalizowane funkcje rozwiązujące ten problem lecz możesz spróbować zmienić porównanie
  1. $val == $row->v
na np.
  1. epsilon = 1E-8;
  2. // epsilon to względnie mała liczba
  3. if ($val - $row->v < epsilon) {}


Ten post edytował pheter 28.10.2009, 21:17:04
Go to the top of the page
+Quote Post
Tryllion
post
Post #5





Grupa: Zarejestrowani
Postów: 15
Pomógł: 0
Dołączył: 29.07.2009

Ostrzeżenie: (0%)
-----


IF ma taką formę bo uciąłem wiele z niego i wkleiłem na forum to co istotne.

Dodałem (float) przy obu wartościach, nadal nie wykrywa, co ciekawe funkcja jest wywoływana w pętli i za pierwszym razem działa.
Przy drugim wywołaniu:
  1. FOR($i=1.0; $i<2; $i+=0.1) {
  2.  
  3. compare_va($i,$i+0.1); // tu się dzieją rózne rzeczy, i między innymi zostaje porównany argument 1 z innym wyciągniętym z bazy
  4.  
  5.  
  6. }
już nie działa, i wszystko jest NIE, za pierwszym równe elementy wykrywa, co może się zmienić w tym czasie, zapis zły ?

EDIT:
zmieniłem wartości na bardziej przystępne, w bazie są co 0.01 a pętla co 0.1 , teoretycznie co 10 powinno wykryć ale wykrywa tylko za 1 wywołaniem tej funkcji !?!
Np. 1.1 jest taki sam jak 1.1
ale już 1.2 nie z 1.2 ! nie rozumiem...

Ten post edytował Tryllion 28.10.2009, 21:27:31
Go to the top of the page
+Quote Post
pheter
post
Post #6





Grupa: Zarejestrowani
Postów: 8
Pomógł: 1
Dołączył: 12.10.2009

Ostrzeżenie: (0%)
-----


Nie wykrywa i wykrywać nie musi, bo 0.1 to wcale nie taka "okrągła" liczba jak się Tobie wydaje, a 0.01 tym bardziej (IMG:style_emoticons/default/winksmiley.jpg)

Przeczytaj posty powyżej, powinno pomóc w zrozumieniu.

Ten post edytował pheter 28.10.2009, 21:34:41
Go to the top of the page
+Quote Post
tua1
post
Post #7





Grupa: Zarejestrowani
Postów: 42
Pomógł: 0
Dołączył: 23.10.2009

Ostrzeżenie: (0%)
-----


Jeśli zależy Ci na wysokiej precyzji zapoznaj się z:

http://www.php.net/manual/pl/ref.bc.php
Go to the top of the page
+Quote Post
thek
post
Post #8





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Cytat(pheter @ 28.10.2009, 21:34:01 ) *
Nie wykrywa i wykrywać nie musi, bo 0.1 to wcale nie taka "okrągła" liczba jak się Tobie wydaje, a 0.01 tym bardziej (IMG:style_emoticons/default/winksmiley.jpg)

Przeczytaj posty powyżej, powinno pomóc w zrozumieniu.
To ja może wspomnę, że najlepsze pod względem "okrągłości" liczby w systemach komputerowych są dane łatwo zapisujące się binarnie, przykładowo 0.125 (IMG:style_emoticons/default/smile.gif) Dlaczego? Zapiszcie sobie tę liczbę binarnie to zobaczycie (IMG:style_emoticons/default/winksmiley.jpg) Dla leniwych wyjaśnię, że kolejne liczby po przecinku to coraz wyższe ułamki dwójki. Tak więc binarnie:
0.1(bin) = 2^-1 = 1/2^1 = 1/2 = 0.5(dec)
0.01(bin) = 2^-2 = 1/2^2 = 1/4 = 0.25(dec)
0.001(bin) = 2^-3 = 1/2^3 = 1/8 = 0.125(dec)
...i tak dalej (IMG:style_emoticons/default/smile.gif)
Te liczby się dodają bez żadnych przybliżeń i można na nich liczyć bezpiecznie i to do ułamków dwójki są zaokrąglane liczby takie 0.75 to binarnie 0.11, ale już 0.76 to już będzie wariacja 0.110101... i dalej z precyzją lecąc jeszcze ileś zer i jedynek byleby jak najbliżej tego być. To sprawia, że dodając dwie takie liczby nie ma gwarancji dokładności. Są systemy, które to obchodzą i to w nich powinno się zapisywać dane jeśli chcesz mieć gwarancję dokładności. Poczytaj może nieco o BCD to Ci się rozjaśni temat. Inaczej zapisują one dane przez co są naprawdę dokładne, ale niestety kosztem zużywanej pamięci.
Go to the top of the page
+Quote Post
Tryllion
post
Post #9





Grupa: Zarejestrowani
Postów: 15
Pomógł: 0
Dołączył: 29.07.2009

Ostrzeżenie: (0%)
-----


ostatecznie wkurzyłem się i dodałem do każdej ze zmiennej liczbowej .'X' , co jak rozumiem przekonwertowało obie wartości na string typu _,__X gdzie _ to cyfra, sztuczka zadziałała, ale i tak jest to rozwiązanie lamerskie, na szybko, ale myślę że do mojego projekciku wystarczy.

dzieki za odpowiedzi
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 23.08.2025 - 10:58