Bug #81601 [Com]: float - (int) float is sometimes bigger than 1

From: Date: Wed, 10 Nov 2021 09:39:26 +0000
Subject: Bug #81601 [Com]: float - (int) float is sometimes bigger than 1
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-237658@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=81601&edit=1

 ID:                 81601
 Comment by:         php at leinertco dot com
 Reported by:        dktapps at pmmp dot io
 Summary:            float - (int) float is sometimes bigger than 1
 Status:             Open
 Type:               Bug
 Package:            Math related
 Operating System:   Linux
 PHP Version:        8.0.12
 Block user comment: N
 Private report:     N

 New Comment:

Try to pass $newLevel as 3rd argument in setXpAndProgress, so you have its value in your logs. Maybe
this will help :/


Previous Comments:
------------------------------------------------------------------------
[2021-11-09 12:14:31] dktapps at pmmp dot io

I do know of several ways to work around it (fmod(f, 1) being the first thing I thought of), but I
thought this should be investigated anyway.

------------------------------------------------------------------------
[2021-11-09 09:58:53] nikic@php.net

If float is larger than INT_MAX, then float - (int) float can trivially be larger than 1. However,
you seem to be working with numbers that are much smaller than that.

I do wonder why this is not implemented as $float - floor($float) though, that seems like the more
natural way to express it, and should avoid edge cases.

------------------------------------------------------------------------
[2021-11-08 20:02:46] dktapps at pmmp dot io

I should clarify, this is definitely NOT a bug in JIT because I've seen this issue  in 7.2, 7.3
and 7.4 historically as well.

I also considered the possibility that -ffast-math may be responsible, but I was unable to reproduce
the problem even with -ffast-math.

All tests were done on x86_64.

------------------------------------------------------------------------
[2021-11-08 19:39:38] dktapps at pmmp dot io

Description:
------------
I've seen this issue recur many times over the last few years, but never figured out exactly
what causes it.

This code: https://github.com/pmmp/PocketMine-MP/blob/3dae87373154ad52ff6c27874f3fd93c9845a8af/src/pocketmine/entity/Human.php#L396
is intended to take a float and split it into its whole-number part (the first argument) and its
fractional part (the second argument).

However, sometimes I see crashes like these show in my telemetry:

Value 1.0323429203787 is outside the range 0 - 1

with a trace like this:

#1 pmsrc/src/pocketmine/entity/Human(396): pocketmine\entity\Human->setXpAndProgress(integer 9,
double 1.0323429203787)
#2 pmsrc/src/pocketmine/entity/Human(409): pocketmine\entity\Human->setCurrentTotalXp(integer
158)

To the best of my understanding, this should be impossible.

For context, passing 158 into setCurrentTotalXp() causes $newLevel to become
float(9.922847983320086), which, when run through the offending code on **my** machine, yields this
result:

(int) $newLevel = int(9)
$newLevel - (int) $newLevel = float(0.9228479833200858)

which looks correct.

I have no idea what causes this problem and have never been able to reproduce it firsthand, but such
issues have appeared so frequently and across several PHP versions that I believe this is a bug in
PHP itself.

Expected result:
----------------
float - (int) float should never be larger than 1.

Actual result:
--------------
float - (int) float is sometimes slightly larger than 1.


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



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


Thread (10 messages)

« previous php.bugs (#237658) next »