ФорумПрограммированиеPHP для идиотов → Ебучее округление чисел с плавающей точкой в PHP 7

Ебучее округление чисел с плавающей точкой в PHP 7

  • viktor228

    Сообщения: 1 Репутация: N Группа: Кто попало

    Spritz 5 марта 2018 г. 7:57

    Друзья, приветствую.

    Сил больше нет бороться с несправедливой хуйней.
    Помогите найти решение.

    Есть 2 сервера:
    Первый: Centos 6, PHP 5.3.3
    Второй: Centos 7, PHP 7.1.14

    Выполнение одного и того же кода дает разный результат.

    Код:

    $iVal = round(4 / 100, 2);
    
    var_export($iVal);
    

    Результат выполнения:
    - на первом сервере: 0.04
    - на втором: 0.040000000000000001

    Подскажите, что с этой хуетой делать ? Т.е. добиться результата на втором сервере идентичного первому.

    P.S. переменная должна остаться числом, не стрингом.

  • Sinkler

    Сообщения: 7958 Репутация: N Группа: в ухо

    Spritz 5 марта 2018 г. 11:03, спустя 3 часа 5 минут 36 секунд

    @viktor228 с разными версиями всегда будут разные результаты, если не здесь так где-то в другом месте. если нужна определённая точность у float, то лучше использовать decimal, для этого есть PHP: BC Math - Manual [php.net] или direvus/php-decimal [github.com] или ещё что-то

  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 5 марта 2018 г. 12:22, спустя 1 час 19 минут

    @viktor228 с разными версиями всегда будут разные результаты

    @Sinkler, да там даже между запусками скрипта на одном сервере и версии могут быть разные результаты) флоат вообще странное гавнище в этом плане :)

    Сапожник без сапог
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz 5 марта 2018 г. 20:59, спустя 8 часов 37 минут 41 секунду

    $ php -v
    PHP 7.1.14 (cli) (built: Mar  2 2018 00:45:11) ( NTS )
    Copyright (c) 1997-2018 The PHP Group
    Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
        with Zend OPcache v7.1.14, Copyright (c) 1999-2018, by Zend Technologies
        with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans
    
    $ php -a
    Interactive shell
    
    php > $a = round(4/100, 2);
    php > var_export($a);
    0.04
    

    сравнивай опции, с которыми скомпилированы версии пхп.

    Спустя 84 сек.

    Ну и да, в пхп нужно делать отдельный тест, который ассертит, что 4/100 == 0.04

    Спустя 13 сек.

    </irony>

    не всё полезно, что в swap полезло
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 6 марта 2018 г. 12:57, спустя 15 часов 58 минут 12 секунд

    Это проблема не PHP как такового, а ограниченности представления вещественного числа. Пыха использует IEEE вещественные типы. IEEE 754 - Wikipedia [en.wikipedia.org]
    Плохо что в PHP нет родного типа с абсолютной точностью для работы с деньгами, например. Флоат подкидывает сюрпризы с округлением.
    Да, bcmath это выход. Не очень элегантно выглядит, так как пришлепка сбоку, но работает как надо. PHP: BC Math - Manual [php.net]

    В PHP точность числа, то есть его длина в байтах, зависит от разрядности интерпретатора. То есть 32бит и 65бит могут оперировать разными типами флоат. А вот чтобы от версии к версии что-то различалось — я не слышал про такое.

    ιιlllιlllι унц-унц
  • master

    Сообщения: 3244 Репутация: N Группа: Джедаи

    Spritz 9 марта 2018 г. 17:11, спустя 3 дня 4 часа 13 минут

    https :// 3v4l .org/8iSWV

    не всё полезно, что в swap полезло
  • Sinkler

    Сообщения: 7958 Репутация: N Группа: в ухо

    Spritz 9 марта 2018 г. 17:24, спустя 13 минут 32 секунды

    не могли определиться smile

  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 12 марта 2018 г. 9:22, спустя 2 дня 15 часов 57 минут

    Сдаётся мне, что разница в var_dump, а не во внутреннем представлении числа. Или я где-то косячу, проверьте:

    https:// 3v4l. org/3vmNV

    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 12 марта 2018 г. 9:47, спустя 25 минут 10 секунд

    короче, если нужно иметь предсказуемый резельтат в строковом представлении вещественного числа, то форматированием надо заниматься самому:
    number_format(), sprintf(), ini_set('precision', …) а не доверять это неким дефолтовым механизмам

    Спустя 120 сек.

    а то, что флоаты не дают точного представления для некоторых чисел, это давно известно. например
    0.1 + 0.2 !== 0.3

    ιιlllιlllι унц-унц
  • Nek

    Сообщения: 109 Репутация: N Группа: Адекваты

    Spritz 23 марта 2018 г. 12:44, спустя 11 дней 2 часа 56 минут

    Согласен с @artoodetoo и остальными ответившими. Также размер int'a (и кажется, точность флоата) в пыхе зависит от разрядности камня/ОС. На 64 бит будет больше чем на 32 бит.
    @viktor228, посмотрите в сторону PHP: Introduction - Manual [php.net]

Пожалуйста, авторизуйтесь, чтобы написать комментарий!