Jump to content
fastsol

Why don't these var_dumps match

Recommended Posts

I'm fighting with a very simple round() that isn't giving me the correct output.  In the example below the first var_dump shows the value of the calculation performed.  The calculation is correct.  Next it runs through the round() native function and comes out incorrect.  Then I run a round() again but set another var to the same value as the first calculation but by simply setting the number rather than letting php do the math.  Then run it through the round() and it comes out to what I expect it should be.

So why is the first one not coming out right?

 

$num = 583.00;
$rate = 1.05500;

$t = (($num * $rate) - $num);
var_dump($t);  //comes out 32.065 float CORRECT

$just_tax = round($t, 2);
var_dump($just_tax); //comes out 32.06 float INCORRECT should be 32.07

$t2 = 32.065; //Explicitly set the same value as $t above
$just_tax2 = round($t2, 2);
var_dump($just_tax2); //comes out 32.07 float CORRECT

 

Share this post


Link to post
Share on other sites

Welcome to the world of floating-point arithmetic.

$t is not actually 32.065. It's some value that's very close but not precisely that. Apparently just short of 32.065, which is why it's rounding down instead of up.

Increase your precision to see what it really is.

$ php -r 'var_dump(583.0*1.055-583.0);'
float(32.065)

$ php -d precision=20 -r 'var_dump(583.0*1.055-583.0);'
float(32.064999999999940883)

When dealing with floating-point numbers, do all your calculations and then round to a precision that is a couple places more than you need. This gets the number into a state closer to what you expected it to be. Then round to any shorter precision you want.

$ php -r 'var_dump(round(583.0*1.055-583.0,2));'
float(32.06)

$ php -r 'var_dump(round(round(583.0*1.055-583.0,7),2));'
float(32.07)

 

Share this post


Link to post
Share on other sites

Thank you for the explanation.  It's certainly something I've not encountered.  This was supposed to be a simple sales tax couple functions that someone found that under certain sets of numbers it was off by 1 cent cause it wasn't rounding up for those instances.  I messed around a bit more and got this to work so far and seems to product the correct amounts for a few different values.  The functions are identical to what I was running before except I changed the 2nd param of the round() to a 3 instead of 2.  Unless you feel this will cause other major issues, I'll probably run with this until I can implement a money type library.

// Returns formatted number with sales tax added
function addSalesTax($num, $rate)
{ return number_format(round(($num * $rate), 3), 2); }

// Returns just the tax amount
function calculateTax($num, $rate)
{ return number_format(round((($num * $rate) - $num), 3), 2); }

$num = 635.00;
$num2 = 583.00;
$rate = 1.05500;

echo addSalesTax($num, $rate);
echo '<br>';
echo calculateTax($num, $rate);
echo '<br><br>';
echo addSalesTax($num2, $rate);
echo '<br>';
echo calculateTax($num2, $rate);

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.