Почему bcmul возвращает число со шкалой, отличной от указанной мной?
Я не могу найти ничего в документации php.net, которая объясняет следующие результаты:
$ php -r 'var_dump(bcsub("0.3", "0.2", 4));'
string(6) "0.1000"
$ php -r 'var_dump(bcmul("0.3", "0.2", 4));'
string(4) "0.06"
Результат вычитания - это именно то, что я и ожидал (я указал 4-значную шкалу, и он дал мне один результат). Результат умножения - нет (я указал 4-значную шкалу, но в результате я получил 2-значную шкалу). Почему разница?
Примечание: я уже знаю, как использовать number_format()
и я тоже знаю что 0.06 === 0.0600
математически. Меня интересует только понимание того, почему BC Math, похоже, действует по-разному в зависимости от масштаба результата.
Примечание № 2: Как упоминалось выше, number_format()
не является ответом на этот вопрос, и ответы, использованные в упомянутом "дублирующем вопросе", все советуют использовать number_format()
, Я прекрасно знаю, что эту функцию можно использовать для форматирования числа с заданной точностью. Мне просто любопытно узнать, ПОЧЕМУ возвращаемые значения для этих функций имеют разные масштабы, а НЕ как их исправить, чтобы они это делали.
1 ответ
В PHP есть функция BCMath bcmul
, Он все еще присутствует в PHP 5.5.7, последней стабильной версии на момент написания этой статьи.
Если вы просматриваете исходный код (BCMath recmul.c в PHP 5.5), вы увидите соответствующую функцию:
void
bc_multiply (bc_num n1, bc_num n2, bc_num *prod, int scale TSRMLS_DC)
{
bc_num pval;
int len1, len2;
int full_scale, prod_scale;
/* Initialize things. */
len1 = n1->n_len + n1->n_scale;
len2 = n2->n_len + n2->n_scale;
full_scale = n1->n_scale + n2->n_scale;
prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
/* Do the multiply */
_bc_rec_mul (n1, len1, n2, len2, &pval, full_scale TSRMLS_CC);
/* Assign to prod and clean up the number. */
pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
pval->n_value = pval->n_ptr;
pval->n_len = len2 + len1 + 1 - full_scale;
pval->n_scale = prod_scale;
_bc_rm_leading_zeros (pval);
if (bc_is_zero (pval TSRMLS_CC))
pval->n_sign = PLUS;
bc_free_num (prod);
*prod = pval;
}
Примечание. Слово "масштаб" относится к количеству цифр после разделителя.
Посмотрите на линию, где prod_scale
назначен. Когда вы вызываете bcmul("0.3", "0.2", 4)
Идя по коду, мы видим: prod_scale = MIN(2,MAX(4,MAX(1,1)));
, так prod_scale
присваивается значение 2
,
И, как и ожидалось, функция возвращает значение с двумя, а не четырьмя цифрами после десятичного знака. В отличие от других функций PHP BCMath (например, см. Строки 63-98 в BCMath doaddsub.c в PHP 5.5), нигде в логике этой функции не добавляются завершающие нули.
Я отправил эту проблему и исправление в систему отслеживания ошибок PHP ( # 66364).