<rmcreative>

RSS

Как узнать, равны ли два float в PHP

6 декабря 2019

Тип float не отличается точностью, страдают от ошибок округления и сравнивать как обычно их нельзя. Почему так отлично написано на специальном сайте floating-point-gui.de.

В PHP узнать, равны ли два float и не нарваться на ошибки можно так:

$equal = \abs($a - $b) < PHP_FLOAT_EPSILON;

PHP_FLOAT_EPSILONмашинный ноль для PHP.

Для PHP < 7.2 можно в качестве epsilon использовать 0.0001.

Комментарии RSS

  1. №11579
    Евгений
    Евгений 06 дек. 2019 г., 16:40:09

    Это во всех нормальных языках так. В ещё более нормальных есть ф-я, которая заменяет вызов abs и сравнение с эпсилон.

    Конечно, такое сравнение не означает, что два флоата равны. Они равны с некой точностью.

  2. №11580
    Stepan
    Stepan 06 дек. 2019 г., 18:36:18

    Или юзать bcmath и не страдать костылями...

  3. №11581
    Дмитрий
    Дмитрий 06 дек. 2019 г., 18:46:45

    Я когда-то хранил деньги в MySQL в типе float, но случилось страшное и с тех пор храню в INT и только копейки :)

  4. №11582
    AndrewBo
    AndrewBo 06 дек. 2019 г., 19:31:20

    Лишняя скобка в конце выражения.

    +1 за использование bccomp.

  5. №11583
    Volodymyr
    Volodymyr 07 дек. 2019 г., 9:06:48

    Сомнительный совет, если честно. Если считать что-то сложнее, чем 1/3*3, результат сильно удивит: дело в том, что погрешность при вычислениях накапливается.

    sin x == sin(x + 2πn), n∈Z

    arcsin(sin x) == arcsin(sin(x + 2πn))

    |x-arcsin(sin x)| < PHP_FLOAT_EPSILON

    а

    |x-arcsin(sin(2π+x))|> PHP_FLOAT_EPSILON

    :-)

    var_dump(abs(pi()/4 - asin(sin(2*pi() + pi()/4))) < PHP_FLOAT_EPSILON);

    в PHP 7.2 даст false

    PS: ну и сравнивая числа с плавающей точкой, нужно понимать, как оно всё внутри устроено. Потому что для

    var_dump(1.0 === 1.0 + PHP_FLOAT_EPSILON/2);
    var_dump(0.5 === 0.5 + PHP_FLOAT_EPSILON/2);
    var_dump(0.25 === 0.25 + PHP_FLOAT_EPSILON/4);

    результат будет true, false, false

  6. №11585
    Евгений
    Евгений 09 дек. 2019 г., 22:13:38

    Я когда-то хранил деньги в MySQL в типе float

    Для этого DECIMAL существует.

  7. №11586
    Дмитрий
    Дмитрий 09 дек. 2019 г., 22:52:06

    Я знаю, но в копейках оказалось удобнее всего

  8. №11896
    sannek8552
    sannek8552 05 июня 2020 г., 15:34:08

    bccomp

    вот только прям на главной стоит предостережение - что сравниваются именно строки. И float будет сначала сконвертирован в строку, а уже потом будет происходить сравнение. Пруф: www.php.net/manual/ru/intro.bc.php

  9. №12288
    Андрей
    Андрей 21 июля 2023 г., 17:58:14

    Я когда-то хранил деньги в MySQL в типе float, но случилось страшное и с тех пор храню в INT и только копейки :)

    Я когда-то хранил деньги в MySQL в типе INT в виде значения, полученного умножением искомого значения на 100... В том числе суммы не только в рублях, а и в других валютах тоже, в числе которых были валюты, где значения всегда целые... Но потом выяснилось, что существуют валюты, в которых после запятой может быть до 3 знаков... А еще, оказывается, есть криптовалюты, где после запятой может быть до 18 знаков... В общем, с некоторых пор храню деньги в DECIMAL. :)) А арифметические операции выполняю с использованием bcmath. Чего и всем рекомендую. :)))

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.