Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][MySQL] Różnice w round
Forum PHP.pl > Forum > Przedszkole
Kshyhoo
Mam następujący problem. Kod:
  1. $row['r1'] = 100;
  2. $row['icc'] = 33;
  3. $row['ml'] = 10;
  4.  
  5. // pętlą w PHP
  6. for ($i=0;$i<$row['ml'];$i++) {
  7. $t = round($row['r1'] * pow(((100 + $row['icc']) / 100), $i));
  8. }
  9.  
  10. // MySQL
  11. $q = "UPDATE gb SET= r1 + ROUND((100 + ".$row['icc'].") / 100, 2) WHERE ...);

daje wyniki:
  1. PHP | MySQL
  2. 100 | 100
  3. 133 | 133
  4. 177 | 177
  5. 235 | 235
  6. 313 | 313
  7. 416 | 416
  8. 553 | 553
  9. 736 | 735 <<<
  10. 979 | 978 <<<
  11. 1302 | 1301 <<<

Skąd różnice? Jak to zgrać?
markuz
Jakiego typu masz to pole w bazie?
Kshyhoo
INT.
markuz
W PHP robisz round do 0
W MySQL round do 2
Nie wiem czy to pomoże ale warto spróbować.

Ew. http://stackoverflow.com/questions/1044658...round-weird-bug
com
Php inaczej zapewne zaokrangla niz mysql. Dla malych liczb tego noe widac a potem juz sa przeskoki. A jak to rozwiazac to nie mam pomuslu biggrin.gif

To jest ten problem ktory potem wychodzi przy == vs === smile.gif
Kshyhoo
Poprzestawiałem co nieco, żeby było identycznie:
  1. $q = $a['r1'] * round(pow(((100 + $a['icc']) / 100), $i), 2);
  2. $q = "UPDATE gb SET= r1 + ROUND((100 + ".$row['icc'].") / 100, 2) WHERE ...);

I ta sama różnica.
pasman
najlepiej napisać własną funkcję zaokrąglającą w mysql, jeśli nie chcesz mieć takich kwiatków:

  1. mysql> SELECT ROUND(2.5), ROUND(25E-1);
  2. +------------+--------------+
  3. | ROUND(2.5) | ROUND(25E-1) |
  4. +------------+--------------+
  5. | 3 | 2 |
  6. +------------+--------------+
Kshyhoo
Cytat(pasman @ 17.03.2015, 21:20:56 ) *
najlepiej napisać własną funkcję zaokrąglającą w mysql, jeśli nie chcesz mieć takich kwiatków:

I zakładałbym wątek, gdybym był tak zaawansowany?
NickOver
Ogólnie php nie zaokrągla liczb matematycznie. Nie wiem za bardzo skąd się to bierze, ale ostatnio musiałem się z tym zmierzyć. Kodu podać Ci nie mogę ale jest on dość prosty.
Zrób funkcje która przyjmuje 3 parametry
  1. $value
  2. $decimal

Potem sprawdzasz czy jest $value jest liczbą, następnie rozbijasz $value na liczby naturalne i to wszystko co jest po kropce, potem rozbijasz to co po kropce na cyfry.
Potem sprawdzasz czy istnieje element tablicy o indeksie $decimal, jeśli tak to sprawdzasz jaką ma wartość. Jeśli powyżej lub równe 5 to podnosisz element tablicy o indeksie $decimal-- o jeden, jeśli nie zostawiasz tak jak jest, tworzysz z tego z powrotem stringa i wyświetlasz. Dodatkowo bardzo łatwo możesz zaadoptować tam zaokrąglanie w górę i w dół.
Crozin
Jeżeli chcesz nieco mocniej zgłębić się w temat czeka Cię nieco lektury:
1. Pozycja niejako obowiązkowa: http://floating-point-gui.de/
2. Po przeczytaniu powyższego dowiesz się, że zwykłe liczby zmiennoprzecinkowe operują jedynie na mocno niedokładnych przybliżeniach i ich wartości praktycznie nigdy nie są prawidłowe (matematycznie).
3. Istnieje wiele różnych sposobów zaokrąglania liczb. Przykładowo czy 2,5 po zaokrągleniu to 2 czy 3? - wcale nie ma tutaj jednoznacznej odpowiedzi.
4. Liczby zmiennoprzecinkowe są niemal zawsze formatowane przed wyświetleniem - ponownie może to być problem zaokrąglenia.
5. Jeżeli chcesz dokładnych wyliczeń musisz korzystać z typu DECIMAL w MySQL albo GMP w PHP-ie.
Kshyhoo
Zauważyłem, że to wina PHP. Każdą z wartości przemnożyłem przez 1,33 i dla 2 miejsc po przecinku otrzymałem:
  1. PHP | *1,33 || MySQL |
  2. -------------------------
  3. 100 | || 100 |
  4. 133 | 133.00 || 133 |
  5. 177 | 176.89 || 177 |
  6. 235 | 235.41 || 235 |
  7. 313 | 312.55 || 313 |
  8. 416 | 416.29 || 416 |
  9. 553 | 553.28 || 553 |
  10. 736 | 735.49 || 735 | < tu PHP błędnie zaokrągla w górę
  11. 979 | 978.88 || 978 |
  12. 1302 | 1302.07 || 1301
Crozin
Cytat
Zauważyłem, że to wina PHP.
1. To nie "wina" PHP.
2. To nie jest błędne działanie.
Kshyhoo
Cytat(Crozin @ 18.03.2015, 13:38:14 ) *
1. To nie "wina" PHP.
2. To nie jest błędne działanie.

Uzasadnij smile.gif Bo to na żywca:
  1. echo 553 * 1.33;

Co ciekawsze, dla:
  1. pow((100 + 33) / 100)

daje:
  1. 1 | 100 | 33 | 1.33
  2. 2 | 100 | 33 | 1.7689
  3. 3 | 100 | 33 | 2.352637
  4. 4 | 100 | 33 | 3.12900721
  5. 5 | 100 | 33 | 4.1615795893
  6. 6 | 100 | 33 | 5.53490085377
  7. 7 | 100 | 33 | 7.36141813551 << i stąd błąd
  8. 8 | 100 | 33 | 9.79068612023
  9. 9 | 100 | 33 | 13.0216125399


Dopiero taki kod daje takie same wyniki:
  1. round(pow(round(((100 + $a['icc']) / 100), 2), $i), 2)
Crozin
Jest wiele czynników:
1. PHP i MySQL mogą przy obliczeniach korzystać z różnej precyzji wykonywanych operacji.
2. Przy wyświetlaniu wyników w obu platformach mogą zostać wykorzystane różne sposoby zaokrąglania wyników.
Kshyhoo
No właśnie. Nie wiem jak, bo nie jestem aż tak zaawansowany, żeby przenieść to tylko na MySQL'a, czyli z każdego wiersza:
  1. nazwa r1 r2 r3 r4 r5 t icr ibt ml
  2. ----------------------------------------------------------------------------
  3. a 30 50 3 5 1 69 30 15 30
  4. b 50 10 20 5 1 69 30 15 30
  5. c 50 10 20 5 1 100 30 15 30
  6. d 60 10 10 30 1 120 30 15 30
  7. e 30 20 5 10 1 55 20 15 40
  8. f 100 80 30 0 1 130 45 25 50
  9. g 160 30 40 100 5 346 0 0 1
  10. h 500 400 150 300 50 3246 15 10 10
  11. i 330 270 450 300 10 3244 35 15 10
  12. j 670 146 500 890 30 4567 35 15 10
  13. k 770 450 1320 100 1 1870 45 30 5
  14. l 10 1500 5 5 10 8935 0 0 1
  15. m 0 3000 5000 0 0 12837 0 0 1

zrobić takie tabelki:
  1. dla nazwa a:
  2. nr r1 r2 r3 r4 r5 t icr ibt
  3. --------------------------------------------------------------------
  4. 1 30 50 3 5 1 69 30 15
  5. 2 60 100 6 10 2 138 60 30
  6. 3 90 150 9 15 3 207 90 45
  7. ...
  8. 29 870 1450 27 145 29 2001 870 420
  9. 30 900 1500 30 150 30 2070 900 450
  10.  
  11. dla nazwa b:
  12. nr r1 r2 r3 r4 r5 t icr ibt
  13. --------------------------------------------------------------------
  14. 1 50 10 20 5 1 69 30 15
  15. 2 100 20 40 10 2 138 60 30
  16. 3 150 30 60 15 3 207 90 45
  17. ...
  18. 29 1200 290 580 145 29 2001 870 420
  19. 30 1500 300 600 150 30 2070 900 450

i to w dodatku PDO, które dopiero co zacząłem smakować wink.gif
  1. $l = $pdo->query("SELECT nazwa, r1, r2, r3, r4, r5, t, icr, ibt, ml FROM tabela");
  2. while($row = $l->fetch()) {
  3. $r1= round($row['r1'] * round(pow(round(((100 + $row['ibr']) / 100), 2), $i) , 2));
  4. }
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.