954,141 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

My PHP math is calculating weird!

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!

nathanpacker
Posting Whiz in Training
234 posts since May 2005
Reputation Points: 10
Solved Threads: 0
 

solve it like this:

echo round($leftover, 2);


Good luck.

mostafadotnet
Junior Poster
157 posts since Jul 2006
Reputation Points: 55
Solved Threads: 11
 

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.

silviuks
Junior Poster in Training
96 posts since Apr 2006
Reputation Points: 10
Solved Threads: 15
 
... 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.

Fest3er
Posting Whiz in Training
242 posts since Aug 2007
Reputation Points: 51
Solved Threads: 35
 

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.

nathanpacker
Posting Whiz in Training
234 posts since May 2005
Reputation Points: 10
Solved Threads: 0
 
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. :)

Fest3er
Posting Whiz in Training
242 posts since Aug 2007
Reputation Points: 51
Solved Threads: 35
 

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.)

nathanpacker
Posting Whiz in Training
234 posts since May 2005
Reputation Points: 10
Solved Threads: 0
 

This article has been dead for over three months

Post: Markdown Syntax: Formatting Help
You