Posting to newsgroup php.internals, you wrote: > [...] > round(), on the other hand, does more than the standard C functions do: > With the additional places argument, it allows to round not only to > integers but to arbitrary places. And this is precisely the thing that > causes all the problems. ;-)
Agree, all the problems you pointed out are due to the different representation of the floating point numbers ("float" for short) against the decimal numbers we humans are used to write. A "float" is typically a 53 bits number (IEEE 754 double precision) that can always be represented exactly as decimal. But the vice-versa it not true, and also very simple decimal numbers do not have a finite "float" rapresentation and must be trunked or rounded. So for example the number 0.1(dec) takes infinite decimal binary gigit once converted to float: 0.1(dec) = 0.00011001100110011001100110011001100110011...(bin) Since IEEE 754 double-precision numbers hold 53 bits, this value has to be rounded to 0.00011001100110011001100110011001100110011001100110011010(bit) (note the rounding on the last 2 binary digits). This latter value is what will be stored in the $f variable after a statement like this one: $f = 0.1; Note too that the value actually stored in $f differs from that we may expect simply reading the source: the difference is very small, but it exists. "Float" values can always be converted back in decimal base with exact precision, so for example in our case the $f variable now contains exactly $f == 0.1000000000000000055511151231257827021181583404541015625(dec) No surprise on that: the "error" was introduced by the PHP parser itself when the statement "$f = 0.1;" was encountered the first time. Now going back to the round() function, it is completely misleading to analize statements like this one echo round(0.285, 2); because here we have actually two conversion problems: 1. The "0.285" decimal number must be converted to "float" at the parse stage of the PHP interpreter, and that brings to "unexpected" results due to the rounding performed in this conversion. 2. The round() function gets a number that already differs from that we see in the source, then it perfoms its calculations thinking at the number as it were a decimal number (multiplying by a power of 10, adding a rounding term, and then trunking the result), and then performs a division by a negative power of 10 that cannot be represented exactly with a float and that must be rounded before the division be performed, and then the result of the division must be rounded again to finally give the result of the function. All these dec-to-bin conversions and "float" roundings sometimes bring to unexpected results as already pointed out in the 42294 bug: we (humans) continue to think at numbers like 0.285 as it they were decimals, but these numbers are actually handled in a completely different base inside the computer. The only real bug is the round() function itself, and number_format() or printf() should be used instead, because these function first convert the binary float to decimal, and then perform the rounding over the decimal number. But remember that also these functions operates on floats, i.e. numbers that already may differ from those we see in the PHP source, so also with these function we can see "strange" results. If we really want a round() function, this function should operate just like number_format() and printf() already do, i.e. returning a string, not a double, or the second argument of the function should be "deprecated" or dropped at all. A final note: programmers concerned with rounding problems and looking for "exact" results while dealing with floating point numbers are usually erroneusly using "float" values to store monetary values as if PHP were a desk calculator, rather than use BCMath or other specialized high-precision library suitable for business applications. Just my 0.019999999999 Euros. Regards, ___ /_|_\ Umberto Salsi \/_\/ www.icosaedro.it -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php