За последние 24 часа нас посетили 17703 программиста и 1659 роботов. Сейчас ищут 853 программиста ...

Проблема округления произведения

Тема в разделе "Прочие вопросы по PHP", создана пользователем Greider, 20 дек 2013.

  1. Greider

    Greider Активный пользователь

    С нами с:
    20 ноя 2013
    Сообщения:
    9
    Симпатии:
    0
    Столкнулся с такой проблемой, для бухгалтерского документа вычисляется сумма НДС.
    Высушил код до минимума, чтобы было понятно, в чем разница:

    Код (Text):
    1. <?php
    2.  
    3. $price = 7732.35;
    4. $nds = 0.18;
    5. $qnty = 25;
    6. $total_1 = round($price*$nds*$qnty, 2);
    7. $total_2 = round($price*$qnty*$nds, 2);
    8.  
    9. echo 'total1:'.$total_1.'
    10. <br>
    11. total2:'.$total_2;
    Получаем на выходе:
    total1: 34 795,58
    total2: 34 795,57

    Мне казалось, что от перемены мест множителей произведение не должно меняться.
    И что сначала должно все перемножиться, а потом округлиться.
    Это у round такой алгоритм, что ему лучше скармливать уже конкретное число, или я где-то туплю??
     
  2. Ke1eth

    Ke1eth Активный пользователь

    С нами с:
    16 мар 2012
    Сообщения:
    1.073
    Симпатии:
    11
    Адрес:
    заблудилса
    number_format()
    я этого раунда наелся при расчетах результатов соревнований, не стоит его использовать там, где нужна точность :)
     
  3. Greider

    Greider Активный пользователь

    С нами с:
    20 ноя 2013
    Сообщения:
    9
    Симпатии:
    0
    Эта функция изначально и была. С ней то же самое.

    Короче говорят, что это особенности вычислений с плавающей точкой...
     
  4. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    чудеса блеать ))))
     
  5. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    total1:34795.58
    total2:34795.58

    Добавлено спустя 2 минуты 47 секунд:
    на двух ОС и разных версиях PHP причем. одна из них 64bit.

    Добавлено спустя 5 минут 15 секунд:
    а вообще правило "от перемены мест результат не меняется" это из абстрактной математики, а не из реальной жизни.

    точность вычислений с плавающей запятой ограничена. и не все числа имеют точное машинное представление. поэтому результат первого произведения может быть уже усечен до N знака, после второго произведения эти потерянные разряды могут стать более заметны или менее заметны в зависимости от множителя.

    Добавлено спустя 2 минуты 47 секунд:
    меня бухгалтер учила: "при расчете на калькуляторе сначала умножай, а потом дели, а не наоборот. иначе точность может пострадать" — это реальность, детка.
     
  6. Your

    Your Старожил

    С нами с:
    2 июл 2011
    Сообщения:
    4.074
    Симпатии:
    7
    Одинаково, проверил тоже.
    Хотя некоторые такие ситуации, можно решить приведением к строке и обратно =)
     
  7. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    у меня на винде 7 (64) разные ) на линкусе не проверял )
     
  8. Ke1eth

    Ke1eth Активный пользователь

    С нами с:
    16 мар 2012
    Сообщения:
    1.073
    Симпатии:
    11
    Адрес:
    заблудилса
    total1:34795.58
    total2:34795.58

    php -v
    PHP 5.4.11 (cli) (built: Feb 12 2013 17:53:30)

    P.S. Linux 3.10.19 :)
     
  9. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Ну так уж быть :)
    total1:34795.58
    total2:34795.58

    #php -v
    PHP 5.4.23 (cli) (built: Dec 11 2013 06:48:07)
    OS: CentOS x86_64
     
  10. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    короче я понял, проблема в винде )

    total1:34795.58
    total2:34795.58

    -bash-4.1$ php -v
    PHP 5.3.3 (cli) (built: Nov 22 2013 10:59:29)

    OS: -bash-4.1$ cat /proc/version
    Linux version 2.6.32-279.el6.x86_64
     
  11. Ke1eth

    Ke1eth Активный пользователь

    С нами с:
    16 мар 2012
    Сообщения:
    1.073
    Симпатии:
    11
    Адрес:
    заблудилса
    Ну в семерке и калькулятор такой, который штатный )
     
  12. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    умножте всё в 10000 раз и работайте с целыми числами на 64 бит хостинге.
    у php же вроде на 64 бит системе 64 бит на числа?
     
  13. YSandro

    YSandro Старожил

    С нами с:
    7 апр 2011
    Сообщения:
    2.523
    Симпатии:
    2
    Если посчитать бинарными функциями произвольной точности:
    Код (PHP):
    1. <?php
    2. $price = '7732.35';
    3. $nds = '0.18';
    4. $qnty = '25';
    5. $total_1 = bcmul(bcmul($price, $nds, 4), $qnty, 4);
    6. $total_2 = bcmul(bcmul($price, $qnty, 4), $nds, 4);
    7. echo 'total1:'.$total_1.'
    8. <br>
    9. total2:'.$total_2; 
    то видим, что округлять приходится число
    Код (Text):
    1. 34795.5750
    Округляем
    Код (PHP):
    1. echo '<div>',round($total_1, 2),'</div>';
    , железно получаем
    Код (Text):
    1. 34795.58