No modelo tax/Sales_Total_Quote_Tax
, existe um método _deltaRound()
que arredonda um preço. Ele adiciona um delta pequeno, para interromper o comportamento não determinístico ao arredondar 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;
}
Mas ele armazena um delta. Se não conseguir encontrar um delta armazenado, cria um. Por quê? Pelo alcatrão que posso dizer, isso leva a resultados diferentes com operações idênticas.
Digamos que temos um $price
de 3.595 e não temos um cache $delta
. À medida que avançamos no método, obteremos $ delta = 0.000001. Em seguida, obtemos $price
= 3.595001, que arredonda para 3,60, portanto, temos um novo $delta
de -0,004999. E retornamos 3,60.
Exceto agora que temos um delta, então vamos fazê-lo novamente, com $price
= 3.595. $price
= 3.595 - 0.004999 = 3.590001
Se arredondarmos, obteremos 3,59. Respostas diferentes.
Parece-me que qualquer algoritmo de arredondamento usado deve pelo menos dar a mesma resposta toda vez que é executado com os mesmos argumentos, mas não desta vez.