В модели tax/Sales_Total_Quote_Tax
есть метод, _deltaRound()
который округляет цену. Добавляет небольшую дельту, чтобы остановить недетерминированное поведение при округлении 0,5.
/**
* Round price based on previous rounding operation delta
*
* @param float $price
* @param string $rate
* @param bool $direction price including or excluding tax
* @param string $type
* @return float
*/
protected function _deltaRound($price, $rate, $direction, $type = 'regular')
{
if ($price) {
$rate = (string)$rate;
$type = $type . $direction;
// initialize the delta to a small number to avoid non-deterministic behavior with rounding of 0.5
$delta = isset($this->_roundingDeltas[$type][$rate]) ? $this->_roundingDeltas[$type][$rate] : 0.000001;
$price += $delta;
$this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);
$price = $this->_calculator->round($price);
}
return $price;
}
Но это хранит дельту. Если он не может найти такую сохраненную дельту, он составляет ее. Почему? Насколько я могу судить, это приводит к разным результатам с одинаковыми операциями.
Допустим, у нас есть $price
3,595, и у нас нет кэшированного $delta
. По мере прохождения метода мы получим $ delta = 0.000001. Затем мы получаем $price
= 3,595001, что округляет до 3,60, поэтому мы получаем новое значение $delta
-0,004999. И мы возвращаем 3,60.
За исключением того, что теперь у нас есть дельта, так что давайте сделаем это снова, с $price
= 3,595. $price
= 3,595 - 0,004999 = 3,590001
Что если мы округлим, мы получим 3,59. Разные ответы.
Мне кажется, что любой используемый алгоритм округления должен, по крайней мере, давать один и тот же ответ каждый раз, когда он запускается с теми же аргументами, но не в этот раз.