php fmod возвращает непригодный результат


fmod(floatval("314.6"), floatval("1.3"))
=> 1.1990408665952E-14

Я более или менее понимаю основную проблему представления чисел в двоичной форме и что-то с IEEE-754. Но: Как бы я получил результат, который можно использовать в практике?

Пример того, чего я хочу достичь: Продавец может определить цену P своего товара, но цена должна быть кратна x:

if (fmod(P, x) != 0) { echo "price must be a multiple of " . x; }

Это было бы так просто, но подход терпит неудачу всякий раз, когда я получаю что-то вроде 1234E-18 в качестве возвращаемого значения fmod(). Что делать в реальной жизни, чтобы легко проверить ценовой интервал без использования пользовательского кода?

Этот или подобные вопросы уже были, но все, что я могу найти, - это объяснения, почему fmod() ведет себя так, как он. Никогда не будет ответа, как решить эту реальную проблему...

Author: muetzenflo, 2018-07-15

1 answers

Проблема здесь в том, что 314.6 точно равно 1.3 * 242, поэтому остаток с плавающей запятой равен нулю, но вы получаете 0.00000000000001199041 из-за неточностей IEEE 754, о которых вы хорошо знаете.

Но не забывайте одно из правил математики с плавающей запятой: вы не можете сравнивать поплавки для равенства небрежно. Если ваши аргументы имеют одну десятичную позицию, вам не нужна точность в 14 позиций в ваших результатах. У вас есть цены: сколько десятичных знаков имеет смысл в вашей валюте? Если вы использовали, например, евро, вы маловероятно использовать более двух (центов), и 1.1990408665952E-14 равно нулю для всех эффектов:

var_dump(round(1.1990408665952E-14, 2));

Двойной(0)

Некоторые люди рекомендуют выполнять всю математику цен, используя целые числа (например, центы вместо евро), чтобы избежать ошибок округления, но большинство реальных проблем возникают из-за очень специфических ошибок:

  • Отображение необработанных поплавков для пользователя (вместо округления и форматирования их).
  • Выполнение необработанных сравнений (if ($foo == $bar)).

...и целые числа не препятствуют округлению ошибки в любом случае (например, расчеты налогов по отдельным позициям, не совпадающие с расчетами по итоговым счетам-фактурам).

 0
Author: Álvaro González, 2018-07-15 16:18:38