php вычисление с плавающей запятой с 2 десятичными знаками

StackOverflow https://stackoverflow.com/questions/1604696

Вопрос

Снова возникла очередная задача по математическим вычислениям.

$a = 34.56

$b = 34.55

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

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

что происходит, так это

$c = $b - $a

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

Я стараюсь использовать number_format($c, 2), но на выходе получается 0.00,

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

насколько я знаю php, number_format способен форматировать только отображение, но значение на самом деле не 2 десятичных знака,

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

Это было полезно?

Решение

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

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

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

$a = 3456;

$b = 3455;

$c = $b - $a;

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

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

Другие советы

Использование round():

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

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

Редактировать: Ладно, я не понимаю, что sprintf() делает это number_format() это не так:

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

против

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

?

Собственные вычисления:

$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    

Я также недавно столкнулся с этой проблемой, когда выполнял вычисления с помощью 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 не делает.

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

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

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

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

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

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

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

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

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

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

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

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

$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.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top