Вычисление php float 2 десятичной точки

Получил математическую задачу.

$a = 34.56

$b = 34.55

$a сделайте некоторые вычисления, чтобы получить эту цифру

$b выполняет округление до ближайшего 0,05, чтобы получить эту цифру

что происходит,

$c = $b - $a

предположительно это будет -0.01, но я повторяю $c, который показывает -0.00988888888888

Я пытаюсь использовать number_format($c, 2), но результат равен 0,00,

Как я могу убедиться, что $a и $b имеют ровно 2 десятичных знака, а сзади нет скрытого числа.

Насколько мне известно, number_format может форматировать только дисплей, но на самом деле это значение не является 2 десятичным,

Я надеюсь, что смогу получить помощь отсюда. Это действительно расстроило меня.

Ответ 1

Попробуйте sprintf ("%.2f", $c);

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

Как было предложено Variable Length Coder, если вы знаете нужную вам точность и не меняете ее (например, когда вы имеете дело с деньгами), было бы лучше просто использовать номера фиксированной точки, т.е. выразить числа как центы чем доллары

$a = 3456;

$b = 3455;

$c = $b - $a;

sprintf ("%.2f", $c/100.0);

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

Ответ 2

Используйте round():

$c = round($b - $a, 2);

Примечание: вы также можете выбрать режим округления.

Изменить: Хорошо. Я не понимаю, что делает sprintf(), что number_format() не:

$c = number_format($b - $a, 2);

против

$c = sprintf("%.2f", $b - $a);

?

Ответ 3

Вы можете очень аккуратно обойти все эти проблемы, просто используя библиотеку bcmath.

Не забудьте прочитать документацию и будьте осторожны, передаете ли вы аргументы как строки или как числовые типы данных.

Ответ 4

Родной расчет:

$a = 34.56;
$b = 34.55;
$c = $b - $a; // -0.010000000000005    

Работает как и ожидалось (используйте всегда функции BC для вычисления реальных чисел, проблема для всех платформ на основе C):

$a = '34.56';
$b = '34.55';
$c = bcsub($b, $a, 4); // -0.0100    

Ответ 5

Я также столкнулся с этой проблемой недавно при выполнении вычислений с помощью float. Например, у меня было 2 поплавки, которые при вычитании и форматировании имели значение -0.00.

$floatOne = 267.58;
$floatTwo = 267.58;
$result = number_format($floatOne - floatTwo, 2);
print $result; //printed a string -0.00

Что я сделал:

$result = abs($floatOne - $floatTwo);// Made the number positive
print money_format('%i', $result); // printed the desired precision 0.00

В моем решении я знаю, что floatOne никогда не будет меньше, чем floatTwo. Функция money_format определяется только в том случае, если у системы есть возможности strfmon, Windows не работает.

Ответ 6

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

Например, если вы выполняете вычисления в поплавках, представляющих Доллары (или вашу любимую валюту), вы можете действительно выполнять свои вычисления в целых центах.

Ответ 7

Если кто-то дойдет до этой страницы с аналогичными проблемами, где вычитание с плавающим числом вызывает ошибку или странные значения. Я хочу объяснить эту проблему немного подробнее. Преступником являются числа с плавающей запятой. И разные операционные системы и разные версии языков программирования могут вести себя по-разному.

Чтобы проиллюстрировать проблему, я объясню, почему с помощью простого примера ниже.

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

Эта проблема даже заняла много жизней два десятилетия назад.

25 февраля 1991 года эта проблема расчета плавающего числа в ракетной батарее MIM-104 Patriot не позволила ей перехватить входящую ракету Scud в Дахране, Саудовская Аравия, в результате которой погибли 28 солдат из 14-го отряда офицера армии США.

Но почему это происходит?

Причина в том, что значения с плавающей запятой представляют собой ограниченную точность. Таким образом, значение может не имеют одинакового строкового представления после любой обработки. Это также включает запись значения с плавающей запятой в script и непосредственно печатайте его без каких-либо математических операций.

Простой пример:

$a = '36';
$b = '-35.99';
echo ($a + $b);

Вы ожидали, что он напечатает 0.01, верно? Но он напечатает очень странный ответ, например, 0.009999999999998

Как и другие числа, числа с плавающей запятой double или float сохраняются в памяти как строка из 0 и 1. Как плавающая точка отличается от целого, заключается в том, как мы интерпретируем 0 и 1, когда хотим посмотреть на них. Существует множество стандартов, как они хранятся.

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

Десятичные числа не представлены в двоичном виде из-за недостаточного пространства. Итак, вы не можете выразить 1/3 точно так же, как 0.3333333..., правильно? Почему мы не можем представлять 0.01, поскольку двоичный номер с плавающей запятой по той же причине. 1/100 - 0,00000010100011110101110000..... с повторением 10100011110101110000.

Если 0,01 хранится в упрощенной и усеченной системой форме 01000111101011100001010 в двоичном формате, когда она переводится обратно в десятичную, она читается как 0,0099999.... в зависимости от системы (64-битные компьютеры дают вам гораздо лучшую точность, чем 32 бита). В этом случае операционная система решает, печатать ли ее, как она видит, или как сделать ее более понятным для человека способом. Таким образом, он зависит от машины, как они хотят его представлять. Но он может быть защищен на уровне языка различными способами.

Если вы отформатируете результат, echo number_format (0,009999999999998, 2); он будет печатать 0.01.

Это потому, что в этом случае вы инструктируете, как его следует читать и как вам нужна точность.