good chemistry is complicated,and a little bit messy -LW PerlMonks

### \$var == 1 fails when \$var = 1

by mjlush (Novice)
 on Sep 20, 2018 at 15:01 UTC Need Help??

mjlush has asked for the wisdom of the Perl Monks concerning the following question:

I've found certain triplets of numbers that added up and put in a variable are, equal to 1, print as 1, are true on looks_like_number, match 1 when evaluated with eq but do not match 1 using using ==.

The order the numbers are added matters, the script below produces output in the form.

```0.688 + 0.289 + 0.023
total is 1
looks like a number
fails on ==
matches on eq

0.688 + 0.023 + 0.289
total is 1
looks like a number
matches on ==
matches on eq

0.559 + 0.380 + 0.061
total is 1
looks like a number
matches on ==
matches on eq

#!/usr/bin/perl
use strict;
use warnings;
use Scalar::Util qw(looks_like_number);

while (<DATA>) {
if (m{^#}) {
print;
next;
}
chomp;
my (\$x, \$y, \$z) = split(m{ });
#   my \$var = \$x + \$y + \$z;
my \$var = \$x;
\$var += \$y;
\$var += \$z;

print "\$x + \$y + \$z\n";
print "total is \$var\n";
if (looks_like_number(\$var)) {
print "looks like a number\n";
}
else {
print "doesn't look like a number\n"
}
if (\$var == 1) {
print "matches on ==\n";
}
else {
print "fails on ==\n";
}
if (\$var eq 1) {
print "matches on eq\n";
}
else {
print "fails on eq\n"
}
print "\n";
}

__DATA__
#FAIL
0.688 0.289 0.023
0.500 0.422 0.078
0.693 0.290 0.017
0.207 0.563 0.230
0.491 0.421 0.088
0.498 0.420 0.082
0.696 0.285 0.019
0.693 0.286 0.021
0.517 0.409 0.074
# ORDER CHANGED
0.688 0.023 0.289
0.422 0.078 0.500
# PASS
0.559 0.380 0.061
0.648 0.314 0.038
0.546 0.414 0.040
0.600 0.348 0.052
0.653 0.311 0.036
0.741 0.245 0.014
0.787 0.201 0.012
0.651 0.318 0.031
0.627 0.331 0.042
```

Replies are listed 'Best First'.
Re: \$var == 1 fails when \$var = 1
by LanX (Sage) on Sep 20, 2018 at 15:08 UTC
floating-point numbers have rounding errors and our decimal system isn't too compatible to binary representation

```DB<8> printf '%.20f', 0.688 + 0.289 + 0.023
0.99999999999999989000

so \$var != 1

Perl's DWIM is sometimes trying to round the string representation, that's why eq seemingly "works".

Rule of thumb, add integers and correct afterwards to the right magnitude.

```  DB<15> p 1 == (688 + 289 + 23) /1000
1

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Why does the order of addition matter?
```DB<8> printf '%.20f', 0.688
0.68799999999999994493
DB<9> printf '%.20f', 0.688 + 0.023
0.71099999999999996536
DB<10> printf '%.20f', 0.688 + 0.023  + 0.289
1.00000000000000000000
DB<11> printf '%.20f', 0.688 + 0.289 + 0.023
0.99999999999999988898
```
PS and thanks for the prompt answer!
Because you are accumulating different rounding errors and (most likely) a shifting mantissa changes the last bit to be rounded.

##### update

Rounding is often not very intuitive, try to avoid if possible.

If you want to track the details you need to look into the binary representation and the underlying C lib.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: \$var == 1 fails when \$var = 1
by hippo (Bishop) on Sep 20, 2018 at 15:09 UTC
Re: \$var == 1 fails when \$var = 1 (lost post)
by LanX (Sage) on Sep 20, 2018 at 23:44 UTC

Well once again.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Well once again

Why ?

Does that link actually answer either of the 2 issues raised by the OP ?
Those 2 issues can be paraphrased as:

1) Why does perl assert that \$x is 1 when \$x != 1 ?
2) How is it that \$x+\$y+\$z != \$x+\$z+\$y ?

Cheers,
Rob
primarily b/c I was worried about the lost post.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

o_0 I saw and upvoted that reply from Laurent_R too…

Re: \$var == 1 fails when \$var = 1
by Anonymous Monk on Sep 20, 2018 at 16:36 UTC

Math::BigFloat will make these calculations precise, though slower.

my \$var = Math::BigFloat->new(\$x) + Math::BigFloat->new(\$y) + Math::BigFloat->new(\$z);

Just make sure to pass them to the Math::BigFloat constructor while they are still strings. If you use them as numbers first you could lose the precision before it can be stored.

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1222720]
Approved by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (2)
As of 2022-08-19 16:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?

No recent polls found

Notices?