bcmath, кажется, дает неправильный ответ на мой расчет

Я не уверен, что я делаю неправильно, но этот расчет

bcscale(20);
echo bcmul(bcdiv('422218', '2388865'), '473');

повторяет «83,59999999999999999670», но любой другой калькулятор дает мне 83,6.

Есть ли способ решить эту проблему или это недостаток bcmath?


person Zzzarka    schedule 22.02.2011    source источник
comment
Это кажется истолкованным примером. Почему бы вам не изменить порядок операций или просто не использовать обычную арифметику PHP с плавающей запятой, если это то, что вы хотите?   -  person mario    schedule 22.02.2011


Ответы (4)


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

Дивизия дает вам:

422218/2388865
0.17674418604651162790697674418604651163

но вы запрашиваете 20 цифр, так что получается 0.1767441860465116279. В этом свете bc дает вам правильный результат:

0.1767441860465116279*473
83.5999999999999999967

"Решение" в этом случае будет состоять в том, чтобы сначала выполнить умножение (что дает вам "всего" 9 цифр), а затем деление:

bcscale(20);
echo bcdiv(bcmul('422218','473'),'2388865');
83.60000000000000000000
person Eelvex    schedule 22.02.2011
comment
Да! правильное решение без обмана. Спасибо! А теперь я думаю, что я пойду и освежу свою математику :) - person Zzzarka; 23.02.2011

Функции bcmath используют арифметику произвольной точности. Расчеты не точны на 100% - они настолько точны, насколько вы просите (вы просили масштаб 20). Поскольку расчеты не точны, вы не всегда можете ожидать, что ответ будет точным.

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

person Mark Byers    schedule 22.02.2011
comment
Да, это имеет большой смысл, спасибо, что вправили мой уставший мозг! - person Zzzarka; 22.02.2011

BCMath дает точный результат. Если вам нужна другая числовая «форма», используйте такие функции, как round(), чтобы изменить ее:

http://php.net/manual/en/function.round.php

Например:

echo round(bcmul(bcdiv('422218', '2388865'), '473'), 1);

Даст вам 83,6.

person Tomasz Kowalczyk    schedule 22.02.2011
comment
Точный результат: 418/5 или 83.6. - person Eelvex; 22.02.2011
comment
Под точным результатом я подразумеваю точное число, вычисляемое компьютером - как кто-то сказал, что оно имеет ограниченную точность, поэтому и результат будет ограниченным. - person Tomasz Kowalczyk; 22.02.2011
comment
@TomaszKowalczyk Я вижу, что я сделал неправильно, и, скорее всего, я буду использовать что-то подобное, чтобы решить эту проблему, нашел хорошую функцию bcround() в другом вопросе ссылка, которую, я думаю, я буду использовать, чтобы сократить точность отображаемых чисел. - person Zzzarka; 22.02.2011
comment
@Tomasz Я думаю, что этот ответ вводит в заблуждение и скрывает основную проблему. В этом случае, например, вы можете просто поменять порядок div и mul и получить точный, правильный результат. Пожалуйста, поскольку это принятый ответ, хотя бы прокомментируйте это. - person Eelvex; 22.02.2011
comment
@Eelvex, как ты имеешь в виду, должен ли я запустить 473 * (422218/2388865)? это швы, чтобы дать мне тот же ответ, что и выше .. - person Zzzarka; 23.02.2011
comment
@Zzzarka: я имею в виду (473*422218)/2388865; см. мой ответ - person Eelvex; 23.02.2011
comment
Ответ больше не принимается, поэтому комментарии не нужны. ;] Но я бы сказал, что если я должен делать какие-либо комментарии - это числовая проблема, но, учитывая этот точный код, мой ответ правильный. - person Tomasz Kowalczyk; 23.02.2011
comment
@Tomasz: Конечно, это правильно; просто round как решение вводит в заблуждение. - person Eelvex; 24.02.2011

Вы указали большую точность (20 цифр), чем может обеспечить большинство калькуляторов. Поэтому они округляют его, скорее всего, до 10 или 15 цифр, что дает 83,5999...99, что округляется до 83,6.

person Marc B    schedule 22.02.2011