Hey, I've got some values that don't seem to be calculating correctly. I've got two numbers, subtracting one from another, and instead of the answer being an exact number, like .06, it's coming out as like .0599999999.

For some background, I'm working with monetary values, and since I'm so new to php and don't know of a better way, I'm simply converting all numbers to cents in the database by multiplying everything by 100, and if I'm spitting it out to the screen for the user, I'm multiplying it by 100. So anyway, I'm taking one number, say $2000 (which is stored in the database as 200000), and assigning it to a variable say called $net.
The other number is being obtained from the sum of numbers in a table, and I'm calling it $sum.

So here's how I'm getting the $net variable. The value in the table that it is pulling is 200000:

$query = mysql_query("SELECT * FROM mytable WHERE id=1") or die(mysql_error());
while($row = mysql_fetch_array($query))
	{
	$net=$row['net']/100;
	}

So at this point, $net=2000. Here's how I get the $sum variable:

$query = "SELECT SUM(allotment) FROM anothertable";
	$result = mysql_query($query) or die(mysql_error());
	while($row = mysql_fetch_array($result))
		{
		$sum=$row['SUM(allotment)']/100;
		}

In this case, $sum=1999.94

So now I want to create a value called $leftover that is equal to $net minus $sum.
So I do this:

$leftover=$net-$sum;

It should end up being .06, but it's not, it's ending up as .059999999. Any clues as to why?


Now I noticed that if in my while statement I set the variables like this:

$sum=$row['SUM(allotment)'];

And

$net=$row['net'];

Then calculate the leftover amount from those like this:

$leftover=($net-sum)/100;

Then it works! Why?

FYI - I even printed out my variables as I went along to check them. Sure enough, it prints out:

$net=2000
$sum=1999.94

So 2000-1999.94 should equal 0.06 right? I just don't understand!

you can also try to use number_format(float $value, int $decimals). the problem with this function is that returns a string so it will help you only for friendly display.

... So 2000-1999.94 should equal 0.06 right? I just don't understand!

To find the best answer, you have to travel 30 years back in time. :) In a nut shell, you don't get exact answer all the time because binary floating point machine arithmetic cannot reproduce all real decimal numbers. Binary gets close, but cannot always be dead-nuts-on. It's been too long, but I'll bet that .06 cannot be exactly represented by a binary floating point number.

See Wikipedia's IEEE Floating Point Standard page for more info.

To find the best answer, you have to travel 30 years back in time. :) In a nut shell, you don't get exact answer all the time because binary floating point machine arithmetic cannot reproduce all real decimal numbers. Binary gets close, but cannot always be dead-nuts-on. It's been too long, but I'll bet that .06 cannot be exactly represented by a binary floating point number.

See Wikipedia's IEEE Floating Point Standard page for more info.

That's an interesting answer. I guess I'm just confused. If you divide something by 100, you end up with two decimal places, period. Shouldn't be that dificult, rught? Well, I think I'm happy with the way I'm doing it now, like I mentioned at the last part of my post, where I do the division by 100 at the very end. I was just curious.

On a side note, anyone have a better way of working with monitary values other than storing them in the database all as pennies? I mean, I kind of like it, it's simple, and easy to understand, just wondering if there's a better way.

That's an interesting answer. I guess I'm just confused. If you divide something by 100, you end up with two decimal places, period. ...

But, grasshopper, you are forgetting that the computer does not operate in the decimal realm. It operates in the binary realm. What you think is 342/100, the computer sees as:
101010110/1100100
What you see as 2-1.94, the computer computes as, generally speaking,
10-1.1111 = .0000111
If you convert 1.1111 (binary) back to decimal, you will get 1.9375.

A silly extension of this (1.94 conversion) to many decimal/binimal places:
1.1111000010100011110101110000101000111101011100001 (binary) =
1.9399999999999995026200849679298698902130126953125 (decimal), and

1.11110000101000111101011100001010001111010111000011 (binary) =
1.94000000000000039079850466805510222911834716796875

You can see that one bit at 49 binimal places still has a not insignificant effect on the value of the number.

And for .06:
0.100110011001100110011 (binary) =
.599999904632568359375 (decimal), and

0.1001100110011001100111 (binary) =
.6000001430511474609375 (decimal)

Only rarely can real decimal numbers be exactly represented by real binary numbers. 'Real numbers' here means floating point numbers, as opposed to whole (integer) numbers. Why? In decimal, the number to the right of the '.' are 1/10, 1/100, 1/1000, etc. In binary, those numbers are 1/2, 1/4, 1/8, 1/16, etc. They only rarely align.

People have tried to get rich adding up these lost millicents and microcents. Well, at least they've tried in the movies. :)

But, grasshopper, you are forgetting that the computer does not operate in the decimal realm. It operates in the binary realm. What you think is 342/100, the computer sees as:
101010110/1100100
What you see as 2-1.94, the computer computes as, generally speaking,
10-1.1111 = .0000111
If you convert 1.1111 (binary) back to decimal, you will get 1.9375.

A silly extension of this (1.94 conversion) to many decimal/binimal places:
1.1111000010100011110101110000101000111101011100001 (binary) =
1.9399999999999995026200849679298698902130126953125 (decimal), and

1.11110000101000111101011100001010001111010111000011 (binary) =
1.94000000000000039079850466805510222911834716796875

You can see that one bit at 49 binimal places still has a not insignificant effect on the value of the number.

And for .06:
0.100110011001100110011 (binary) =
.599999904632568359375 (decimal), and

0.1001100110011001100111 (binary) =
.6000001430511474609375 (decimal)

Only rarely can real decimal numbers be exactly represented by real binary numbers. 'Real numbers' here means floating point numbers, as opposed to whole (integer) numbers. Why? In decimal, the number to the right of the '.' are 1/10, 1/100, 1/1000, etc. In binary, those numbers are 1/2, 1/4, 1/8, 1/16, etc. They only rarely align.

People have tried to get rich adding up these lost millicents and microcents. Well, at least they've tried in the movies. :)

Ah, gotcha. Well then, how do calculators do it so well dang it? (you don't have to answer that. Semi-rhetorical question.)

This article has been dead for over six months. Start a new discussion instead.