Rounding -- was [PHP] round to nearest 500?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



At 8:40 PM +0100 2/13/07, Satyam wrote:
----- Original Message ----- From: "Jon Anderson" <jon@xxxxxxxxxxxxxxxxxx>
The reason is simple:
0: No rounding. It's already there. (8.0 doesn't need to be rounded to 8 - it already *is* 8.)
1-4: You round down -> 4 of 9 times you round down.
5-9: You round up -> 5 of 9 times you round up.

That is not quite correct, there is no such 4 ninths agains 5 ninths. You round down in the interval from 0 to0.499999999 and you round up from 0.5 to 0.9999999. If you substract the .5 from 0.99999, you get 0.4999999 so it is about the same interval for both.

If there is any difference, and actually there is, is because any number is, in reality, truncated, and not rounded, at some point. Depending on the number of bits of the mantissa, it might be a long way off, but eventually, it will happen, and that one is truncation, nor rounding, and if you repeat any calculation involving fractional numbers, it will eventually add up to something noticeable.

Actually, there is the further problem that computers actually use binary, not decimal, so they cannot represent decimal numbers exactly. To offer an example of what I'm talking about, 1/3, which results in a never ending 0.333333 is exactly 0.1 in base 3 arithmetic! Conversely, many 'round' numbers in our decimal notation are not 'round' in binary and viceversa. So it is all the piling of lots of rounding errors in real-life number representations that produce the error, not the mathematics of rounding, which actually work in an abstract world of infinitely precise number representations (in other words, infinite bits to represent any numbers).

Satyam

Satyam and Jon:

Actually, both of you are correct.

The bias in rounding comes from the concept of rounding down for numbers 0-4 and rounding up for number 5-9. Please, let's take a critical look at that premise.

For zero, as Jon claims, there is no rounding at all -- you don't do anything. You can't include zero as one of the conditions that claims to do something when it doesn't do anything. It doesn't do anything to the data at all! So, to include zero in a rounding scheme is fundamentally flawed. Satyam, put your objections on hold for a moment and consider.

For values one to four, you round down. So, you have four conditions where you actually do something to the data, you round down.

For values five to nine, you round up. So, you have five conditions where you actually do something to the data, you round up.

If you do anything four times one way and five times the other, you're going to introduce a bias.

So, how do you get around this?

One way is to use Statistical (Stochastic) rounding. It singles out five as being the culprit for this bias. It uses the even/odd rule of the preceding digit to determine which direction to round 5. If the value is even, then it rounds up -- whereas if the value is odd, then it rounds down. (or reverse the rounding, it doesn't matter as long as you are consistent).

For all other values (1-4 and 6-9, note four each direction) the typical rounding is observed.

Examples of it at work:

0.5 -> 1  (zero is treated as even -- see below *)
1.5 - >1
2.5  -> 3
3.5 -> 3
4.5 -> 5
5.5 ->5
6.5 -> 7
7.5 -> 7
8.5 -> 9
9.5 - 9

From this distribution (actually all you'll ever need to prove this), you can see we have just as many cases that round up as we do that round down -- thus, the aforementioned rounding bias has been reduced. The negative range is just a mirror image.

Now, one can try to pump this algorithm through a PHP loop to see the difference (as I've tried) but you'll find that there are rounding errors (due to what Satyam said about computers representing decimal numbers exactly) that will prohibit making the algorithm work as described.

For example, the "built-in" functions, such as intval(), do not work the way you might expect them to work. Try using this statement:

$t =intval(($number - intval($number)) * 10);

It works fine if the number is 89441560.5  -- it returns 5.

However, if the number is 139690837.6 -- returns 5 instead of 6.

And the list goes on of examples where the result isn't quite what's expected.

If you look deeper into this, you'll find the rounding problem doesn't really have a solution, but rather it's a compromise. I'm sure that Rasmus Lendorf could shed some light on this -- remember the "When is z != z?" argument I started many moons ago? I think this is along the same lines.

Perhaps the round() function takes all this into account, but I don't know and therein lies my suspicion.

Cheers,

tedd

*By definition, any number that can be divided by two and leaves no remainder is even. Some say that the value is undefined, but for sake of this argument, it's considered even. Besides, symmetry in nature is more desirable.
--
-------
http://sperling.com  http://ancientstones.com  http://earthstones.com

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux