Bug #75644 [Wfx]: round(362.42499999999995, 2) gives incorrect result

From: Date: Sat, 10 Jul 2021 11:38:07 +0000
Subject: Bug #75644 [Wfx]: round(362.42499999999995, 2) gives incorrect result
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-234944@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=75644&edit=1

 ID:                 75644
 User updated by:    markamery at btinternet dot com
 Reported by:        markamery at btinternet dot com
 Summary:            round(362.42499999999995, 2) gives incorrect result
 Status:             Wont fix
 Type:               Bug
 Package:            Math related
 Operating System:   Ubuntu
 PHP Version:        7.1.12
 Assigned To:        cmb
 Block user comment: N
 Private report:     N

 New Comment:

Oh, wow. So, if I'm understanding correctly, the cause of this behaviour is that round()
*deliberately* does "pre-rounding", where it rounds the float you give it to 15
significant figures first, and *then* rounds the result of *that* step to the number of decimal
places you ask for. The motivating idea seems to be to treat floats as if they were decimal numbers
with 15 significant figures of precision, and treat the subsequent decimal digits as being nonsense.

(On top of that, the rounding to 15 sig figs is itself done in a dubious way, where the value is
multiplied up by a power of 10 to get 15 sig figs before the decimal point, then rounded to an
integer. But that multiplication can change what the 15th significant digit will come out as when
you round. For instance, 362.42499999999949 to 15 SF should be 362.424999999999, but because
362.42499999999949 * 100000000000000 gives 36242499999999952, flipping the 16th sig fig from a 4 to
a 5, we instead get 362.425000000000.)

I'm not even sure how one would go about clearly documenting this function's behaviour as
it currently stands. What guarantees do we have? Rounding direction will be correct as long as the
value is no more than 0.5 * 10^-14 away from the midpoint, maybe? Or that if you parse a decimal
number containing no more than 15 digits to a float, then round it, you'll get the result that
is correct for the decimal value you parsed? I'm not confident that even those things are
guaranteed to be honest.


Previous Comments:
------------------------------------------------------------------------
[2021-07-09 15:40:17] cmb@php.net

TIL that PHP uses an elaborate rounding algorithm[1], and due to
this, you get the wrong result.  Changing this would require an
RFC (and the RFC author would need to figure out a way how to
support other modes than HALF_EVEN), but fortunately the float to
string conversion has not been "fixed", so you can use e.g.
printf() to get the desired results.

Anyhow, while rounding to two decimals might have practical use
cases, monetary arithmetic is not one of them.

[1] <https://wiki.php.net/rfc/rounding>

------------------------------------------------------------------------
[2017-12-06 22:47:34] markamery at btinternet dot com

Description:
------------
Even though 362.42499999999995 is less than 362.425 (i.e. the internally-stored IEEE-754
representation of 362.42499999999995 has a value less than 362.425), round(362.42499999999995, 2)
gives 362.43

It should give 362.42

Test script:
---------------
<?php
$x = 362.42499999999995;
echo $x . "\n";
echo round($x, 2) . "\n";
ini_set('precision', 999);
echo $x . "\n";
echo round($x, 2) . "\n";


Expected result:
----------------
362.425
362.42
362.424999999999954525264911353588104248046875
362.42000000000001591615728102624416351318359375


Actual result:
--------------
362.425
362.43
362.424999999999954525264911353588104248046875
362.43000000000000682121026329696178436279296875



------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=75644&edit=1


Thread (4 messages)

« previous php.bugs (#234944) next »