2 replies [Last post]
z3b
z3b's picture
Offline
Joined: 08/15/2007
Juice: 48

Came across a weird rounding problem this morning.
Had an order of $3.98 and a line item of -$3.98 (from gift certificate module)
uc_order_get_total() returned 4.4408920985006E-16 instead of zero.

function uc_order_get_total($order, $products_only = FALSE) {
  $total = 0;

  if (is_array($order->products)) {
    foreach ($order->products as $product) {
      $total += $product->price * $product->qty;
    }
  }

  if ($products_only) {
    return $total;
  }

  $total += uc_line_items_calculate($order);

  $result = module_invoke_all('order', 'total', $order, NULL);
  foreach ($result as $key => $value) {
    $total += $value;
  }
  return $total;
}

Been checking all values in db plus added a ton of drupal_set_message() to debug, but everything seems correct but the addition result... (no problems with uc_line_items_calculate())

Seems to me it's a PHP problem, had to insert this line before returning the total to fix it.

$total = round($total,2);

That being said, I'm not really fan of this fix and I'm a bit scared to overwrite it on next UC update. Any opinion/advice on this ?

Thanks

Lyle's picture
Offline
AdministratoreLiTe!
Joined: 08/07/2007
Juice: 6841
Re: uc_order_get_total() rounding problem

Due to the way floating point math works, it's almost impossible to get extremely accurate answers. In fact, the closer to 0 you get, the more noticeable it is.

There are two ways to deal with it, depending on what you want to do with the value:
1. Round
2. Allow for a margin of error in comparisons.

uc_currency_format() automatically rounds the input to two decimal places, so if you're displaying, this function should be used.

Never test float values for equality with 0. Instead, make sure it's smaller than a reasonably small number. For money, 0.001 is a good candidate.

If Ubercart needs to do one of these things, let us know where the value is being used.

z3b
z3b's picture
Offline
Joined: 08/15/2007
Juice: 48
Re: Re: uc_order_get_total() rounding problem

Ok, so then the problem is in the "Gift Certificate" module which uses.

if ($total != 0)

Thanks Lyle!