-
Notifications
You must be signed in to change notification settings - Fork 52
Prevent accurate comparison of floating-point numbers #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent accurate comparison of floating-point numbers #38
Conversation
460df80
to
a9f590b
Compare
a9f590b
to
4f11909
Compare
4f11909
to
07e5b84
Compare
Just a note: abs($left - $right) < $epsilon
does not always work. See for example nette/tester#68
Edit: Although i guess it depends on how you compute $epsilon
. If you scale it with the $left
and $right
it should work just fine.
jasny
commented
Nov 20, 2018
@ondrejmirtes Here a realistic case where this would cause an issue.
function isPaid(array $amounts, array $payments) { $total = array_sum($amounts); $paid = array_sum($payments); return $paid >= $total; } $amounts = [0.1, 0.2]; $payments = [0.15, 0.15]; var_dump(isPaid($amounts, $payments)); // false
@CzechBoy Forbidding floats altogether and avoiding errorneous comparison by equality are two different use cases.
@Majkl578 sure, I only send link to similiar library.
32c1d88
to
e193d17
Compare
caf5ad7
to
4c0f978
Compare
Hi, I'm not sure about this one, I worry it'd be too annoying. AFAIK floats are precise to a certain number of decimals so for example if you compare two floats after rounding them to one decimal place (like 1.3
) then comparing them with ===
is fine.
But feel free to publish this as a separate package, I'm certain some people would like it. I'm gonna wait some time before closing for feedback from the others.
AFAIK floats are precise to a certain number of decimals so for example if you compare two floats after rounding them to one decimal place (like 1.3) then comparing them with === is fine.
The (need of / absence of) rounding in first place is the problem here as it's something people usually don't do / forget.
E.g.:
php > var_dump(.1 + .2 == .3); bool(false)
IMO PHPStan should warn about this code, possibly directly in core, not only in phpstan-strict-rules. 🤔
https://andy-carter.com/blog/don-t-trust-php-floating-point-numbers-when-equating
The linked article shows that $test == 0.3
can be valid code but it would be marked with an error by this PR.
The linked article shows that
$test == 0.3
can be valid code but it would be marked with an error by this PR.
Not sure bcadd(0.1, 0.2, 1);
should a real recommended way.
Most of the time you'll sum variable bcadd($a, $b, 1);
, then you don't know how much significative numbers is needed because 0.3001
and 0.3
should not be considered the same.
I find an article recommending (string) $test == '0.3'
to avoid issue with float comparison.
Prevent situation when comparison return can unexpected result. For example:
php > $a = 0.15 + 0.15; php > $b = 0.1 + 0.2; php > $c = 0.3; php > var_dump($a === $b); bool(false) php > var_dump($b == $c); bool(false) php > var_dump($b <= $c); bool(false)
@dmytro-dymarchuk What about the comparison with 0.0
?
Can we have unexpected behavior with code like
$float === 0.0;
$float !== 0.0;
$float >= 0.0;
$float <= 0.0;
Or should it be a special case ignored by your rule ?
$floatAmount1 = 0.1; $floatAmount2 = 0.2; $sumFloat = $floatAmount1 + $floatAmount2; echo "Sum using float: $sumFloat\n"; // Output: Sum using float: 0.30000000000000004 $stringAmount1 = '0.1'; $stringAmount2 = '0.2'; $sumString = bcadd($stringAmount1, $stringAmount2, 1); echo "Sum using string: $sumString\n"; // Output: Sum using string: 0.3
So yeah, either bcmath and strings, or better yet a value object:
https://github.com/php-collective/decimal-object
tborealis
commented
Nov 23, 2023
Having caused myself some serious headaches with float comparisons that work in some situations but not others, I'd be very much behind this being included here. I don't see it as being any more annoying than requiring booleans in conditionals.
Uh oh!
There was an error while loading. Please reload this page.
Prevent situation when comparison return can unexpected result. For example: