Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> floor źle działa, niemożliwe? A jednak!
php programmer
post
Post #1





Grupa: Zarejestrowani
Postów: 1 045
Pomógł: 5
Dołączył: 8.11.2004
Skąd: trójmiasto

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


Oto kod
  1. <?php
  2. echo $liczba = 7/0.14;
  3. echo '<br />';
  4. echo floor($liczba);
  5. ?>


Który wyświetla mi
50
49

Jakoby zaokrągleniem w dół liczby 50 było 49!
Czy ktoś wie dlaczego mi tak robi i jak to ominąć.
Go to the top of the page
+Quote Post
cicik
post
Post #2





Grupa: Zarejestrowani
Postów: 219
Pomógł: 5
Dołączył: 18.07.2006
Skąd: Piekary Śląskie

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


W sumie dziwne bo jak za $liczba podstawi się 50 to jest OK.
Podejrzewam, że na naszych niedoskonałych procesorach 7/0.14 = 49.999999999999999999 (to tylko przykład). Zwykłe wyświetlanie wyniku pewnie zaokrągla na którymś miejscu po przecinku i wychodzi 50. Natomiast floor pewnie bierze całą liczbę i zaokrągla w dół. Aczkolwiek sprawa ciekawa. W wolnej chwili zobaczę jak to wygląda w innych językach i kompilatorach.
Go to the top of the page
+Quote Post
grzemach
post
Post #3





Grupa: Zarejestrowani
Postów: 121
Pomógł: 4
Dołączył: 9.06.2007
Skąd: Kielce

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


a musisz koniecznie wykorzystywać floor? nie mozesz np spróbować round()?
Go to the top of the page
+Quote Post
php programmer
post
Post #4





Grupa: Zarejestrowani
Postów: 1 045
Pomógł: 5
Dołączył: 8.11.2004
Skąd: trójmiasto

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


round to nie floor,
ale chyba potraktuje to strpos i substr
Go to the top of the page
+Quote Post
cicik
post
Post #5





Grupa: Zarejestrowani
Postów: 219
Pomógł: 5
Dołączył: 18.07.2006
Skąd: Piekary Śląskie

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


Kod C#, kompilator VS .Net 2005, procesor Intel Centrino, system Windows XP Professional

  1. <?php
  2. double liczba = 7./ 0.14;
  3. Console.WriteLine(liczba);
  4. Console.WriteLine(Math.Floor(liczba));
  5. ?>


Wynik:
  1. <?php
  2. 50
  3. 49
  4. ?>


Kod C++, kompilator VS .Net 2005, procesor Intel Centrino, system Windows XP Professional

  1. <?php
  2. double liczba;
  3. liczba = 7./ 0.14;
  4. cout << liczba << endl;
  5. cout << floor(liczba) << endl;
  6. ?>


Wynik:
  1. <?php
  2. 50
  3. 49
  4. ?>


Pod Demianem pracującym na AMD Athlonie XP 2500+ kod w C++ daje taki sam zły wynik.

Ten post edytował cicik 8.08.2007, 08:17:53
Go to the top of the page
+Quote Post
Grzyw
post
Post #6





Grupa: Zarejestrowani
Postów: 561
Pomógł: 75
Dołączył: 19.08.2004
Skąd: Wrocław

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


Analogie to powyższego przykładu spotkałem w literaturze swego czasu. Błąd faktycznie bierze się z niedoskonałości liczenia procesorów, jest nie do wyeliminowania drogą bezpośrednią, wynik zawsze będzie błędny.
Go to the top of the page
+Quote Post
cicik
post
Post #7





Grupa: Zarejestrowani
Postów: 219
Pomógł: 5
Dołączył: 18.07.2006
Skąd: Piekary Śląskie

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


Pewnie kluczem do rozwiązania zagadki jest to, że liczba 0.1 jest liczbą niewymierną w systemie dwójkowym, a 0.14 = 0.1 + 0.04.
Procesory stosują różne triki, żeby tę cechę wyeliminować ale jak widać nie zawsze działa.

Aczkolwiek kiedyś miałem taki problem, że pisałem program do obliczania jakimi monetami wydać resztę w sklepie (na jakiś konkurs to było). Chodziło to aby badać reszty z dzielenia. No i generalnie na Intelach wyniki dzielenia (albo zaokrąglania - to dawno było) były inne od tych uzyskanych na AMD - tym samym kodem źródłowym!!! To mnie wtedy dość mocno zaskoczyło bo procesory przechodzą bardzo ostre testy na poprawność działania jednostki arytmetycznej, zwłaszcza tej zmiennoprzecinkowej. Historia o tym jak kiedyś wybuchła jakaś rakieta kosmiczna bo któryś Pentium źle liczył jest dość znana.

Ten post edytował cicik 8.08.2007, 09:17:08
Go to the top of the page
+Quote Post
likemandrake
post
Post #8





Grupa: Zarejestrowani
Postów: 175
Pomógł: 17
Dołączył: 23.06.2006

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


Problem polega wlasnie na tym co mowil moj poprzednik, aby ten temat sobie blizej przyblizyc, nalezy poczytac o tym, jak binarnie sa kodowane liczby po przecinku i mowa tu o liczbach zmiennoprzecinkowych. Cala sprawa kreci sie wtedy wokol kodowania FP2.

Na szybko mowiac, dla przykladu mamy taki ciag binarny (podzielony na grupy):

1|101|100101

liczba w pierwszej grupie jest to znak (+/-)
liczby w drugiej jest to cecha, inaczej zakres liczby
liczby w trzeciej grupie to mantysa, jest to tak naprawde nasza liczba, tyle ze zamieniona tak, zeby byla po przecinku

Jest wzór, wg którego obliczamy (odkodowujemy) liczbę zawartą w tym kodzie, ale ze względu na użyte potęgi, nie podałem go tu, a więc zainteresowanych odsyłam do google.pl

Chodzi o to, ze im mamy część całkowitą dalszą od zera, tym jej wartość po przecinku staje sie mniej dokladna i coraz bardziej zaokraglana wraz ze zwiększaniem tej odległości.

Co do problemu postawionego w tym poście, mam rozumieć, że w obu przypadkach chcemy uzyskać liczbę 50?
Go to the top of the page
+Quote Post
Kosmi
post
Post #9





Grupa: Zarejestrowani
Postów: 23
Pomógł: 0
Dołączył: 24.07.2006

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


Cytat(php programmer @ 8.08.2007, 08:35:09 ) *
Oto kod
  1. <?php
  2. echo $liczba = 7/0.14;
  3. echo '<br />';
  4. echo floor($liczba);
  5. ?>


Który wyświetla mi
50
49

Jakoby zaokrągleniem w dół liczby 50 było 49!
Czy ktoś wie dlaczego mi tak robi i jak to ominąć.


Na szybko może tak:

  1. <?php
  2. echo $liczba = round(7/0.14,6);
  3. echo '<br />';
  4. echo floor($liczba);
  5. ?>


Wynik:
50
50
Musiałbyś jedynie dobrze dobrać dokładność zaokrąglenia.
Go to the top of the page
+Quote Post
Ludvik
post
Post #10





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

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


To nie ma sensu. Liczba 50.6 zostanie zaokrąglona do 51, a nie o to chodzi.

php programmer: Próbowałeś rzutowania na integer? Rzuć okiem, ja w tej chwili nie mam jak tego sprawdzić...
Go to the top of the page
+Quote Post
Kosmi
post
Post #11





Grupa: Zarejestrowani
Postów: 23
Pomógł: 0
Dołączył: 24.07.2006

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


Cytat(Ludvik @ 8.08.2007, 11:24:02 ) *
To nie ma sensu. Liczba 50.6 zostanie zaokrąglona do 51, a nie o to chodzi.

php programmer: Próbowałeś rzutowania na integer? Rzuć okiem, ja w tej chwili nie mam jak tego sprawdzić...


  1. <?php
  2. echo $liczba = round(50.6,6);
  3. echo '<br />';
  4. echo floor($liczba);
  5. ?>


Wynik:
50.6
50

Przez to pisałem o dokładności zaokrąglenia.

Pozdrawiam
Kosmi
Go to the top of the page
+Quote Post
akubiczek
post
Post #12





Grupa: Zarejestrowani
Postów: 189
Pomógł: 0
Dołączył: 4.07.2004
Skąd: z neostrady

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


Cytat(Ludvik @ 8.08.2007, 11:24:02 ) *
To nie ma sensu. Liczba 50.6 zostanie zaokrąglona do 51, a nie o to chodzi.

Jakie 50.6? Tam jest zaokrąglanie z dokładnością do 6 miejsc po przecinku. I wydaje się to być dobrym pomysłem.

Poza tym dodam jeszcze od siebie - zamienić dzielenie na mnożenie:

  1. <?php
  2. echo $liczba = 7*(1/0.14);
  3. echo '<br />';
  4. echo floor($liczba);
  5. ?>


50
50
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: 24.08.2025 - 01:33