In the model tax/Sales_Total_Quote_Tax
, there is a method _deltaRound()
that rounds a price. It adds a small delta, to stop nondeterministic behaviour when rounding 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;
}
But it stores a delta. If it cannot find such a stored delta, it makes one up. Why? As tar as I can tell, this leads to different results with identical operations.
Let's say we have a $price
of 3.595, and we do not have a cached $delta
. As we go through the method, we will obtain $delta = 0.000001. We then get $price
= 3.595001, which rounds to 3.60, so we have a new $delta
of -0.004999. And we return 3.60.
Except now we have a delta so let's do it again, with $price
= 3.595. $price
= 3.595 - 0.004999 = 3.590001
Which if we round, we get 3.59. Different answers.
It seems to me that any rounding algorithm used should at least give the same answer every time it is run with the same arguments, but not this time.