За последние 24 часа нас посетили 63396 программистов и 1584 робота. Сейчас ищут 788 программистов ...

Округление 0.5 — что происходит неправильно?

Тема в разделе "PHP для новичков", создана пользователем Moor, 24 мар 2020.

  1. Moor

    Moor Новичок

    С нами с:
    1 мар 2020
    Сообщения:
    23
    Симпатии:
    0
    Адрес:
    Latvia
    Попалась мне задачка, которую не могу расколдовать. Надеюсь и упаваю на помощь сообщества.
    Итак, надо округлить до 2 знаков после запятой значение выражения 27.26×1.21. До округления получается 32.9849, после округления — какая-то чепуха. Потому что должно быть 32.99, а возвращает 32.98. При этом округление 0.5 до целых возвращает вовсе не 0, а 1.
    PHP:
    1. echo 27.26*1.21; // = 32.9846
    2. echo number_format(27.26*1.21,3); // = 32.985
    3. echo number_format(27.26*1.21,2); // = 32.98
    4. echo bcmul(27.26, 1.21, 2); // = 32.98
    5. echo number_format(0.5); // = 1
    6. echo number_format(32.985,2); // = 32,99
    Подскажите, пожалуйста, что с этой бедой делать? Округлять сначала до трёх после запятой, а потом полученние до двух? Или есть всё же более разумный способ, который мне не удалось нагуглить?
     
  2. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.866
    Симпатии:
    753
    Адрес:
    Татарстан
  3. Moor

    Moor Новичок

    С нами с:
    1 мар 2020
    Сообщения:
    23
    Симпатии:
    0
    Адрес:
    Latvia
    @ADSoft согласен, конечно, но round ситуации не меняет никак:
    PHP:
    1. echo round(27.26*1.21, 2); // = 32.98
    2. echo round(27.26*1.21, 2, PHP_ROUND_HALF_UP); // = 32.98
     
  4. Artur_hopf

    Artur_hopf Старожил

    С нами с:
    7 май 2018
    Сообщения:
    2.264
    Симпатии:
    405
    Вы объясните почему должно быть 32.99?
    PHP:
    1. $s = 27.26*1.21;
    2. echo round($s, 2);
     
  5. Moor

    Moor Новичок

    С нами с:
    1 мар 2020
    Сообщения:
    23
    Симпатии:
    0
    Адрес:
    Latvia
    Потому что пятерка округляется вверх: 32.9846 = 32.985 = 32.99. От 0 до 4 — в меньшую сторону, от 5 до 9 — в большую.
    round(32.9846, 3) вернет 32.985.
    round(32.985,2) вернет 32.99.
    Почему round(32.9846, 2) возвращает 32.98?
     
  6. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    @Moor в твоем примере в number_format() ты передаешь 32.985 в то время как 27.26*1.21 = 32.9846. Поэтому получается 32.99. Функция round() даст тот же результат.
    По математическому правилу, 32.984 должно округляться до 32.98.
    Чтобы понять, почему это так, вот в качестве примера числа 0.45. Оно не округляется до единицы. До единицы округляется как минимум 0.5, которое больше, чем 0.45.
    --- Добавлено ---
    @Moor вот классный материал на тему ошибки двойного округления.
     
  7. Moor

    Moor Новичок

    С нами с:
    1 мар 2020
    Сообщения:
    23
    Симпатии:
    0
    Адрес:
    Latvia
    @[vs] интересно, я всегда считал, что округление происходит поэтапно с конца, пока не округлится соответствующий разряд. Ну то есть 0.46 при округлении до целых сначала округляется до 0.5, потом до 1. Окей, надо признать, что был неправ.