Skip to content
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

is this a bug? #6569

Closed
p5pRT opened this issue Jun 18, 2003 · 15 comments
Closed

is this a bug? #6569

p5pRT opened this issue Jun 18, 2003 · 15 comments

Comments

@p5pRT
Copy link

p5pRT commented Jun 18, 2003

Migrated from rt.perl.org#22725 (status was 'resolved')

Searchable as RT22725$

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From giswty@nus.edu.sg

Hi there,

I'm new to perl and was writing a small program. Found something funny. When I try to add this particular sequence of numbers (0.4+0.3+0.2+0.1), it does not add up to one. (falls to the else loop).
The version of perl compiler I am using is perl 5.6.1 on windows and solaris

If I change these numbers to like 0.25+0.5+0.25 OR 0.9+0.1 etc then no problem.

Here is the code snippet​:

*************************
use strict;
use warnings;

my $tmp = 0.4+0.3+0.2+0.1;
if ($tmp == 1) {
  print "Equals one", "\n";
}
else {
  print "Not equal to one", "\n";
}
exit;

thanks!
Marie
email​: marie_wong@​gmx.net

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From Robin.Barker@npl.co.uk

This is not a bug, see C<perldoc -f decimal> for a full explanation.

If you add a line after 'print "Not equal to one", "\n";'
  printf "\$tmp = %.20f\n", $tmp;
the output is​:

Not equal to one
$tmp = 0.99999999999999988898

Robin
-----Original Message-----
From​: Marie Vivian Wong Tzu Yenn [mailto​:perlbug-followup@​perl.org]
Sent​: 18 June 2003 04​:26
To​: perl5-porters@​perl.org
Subject​: [perl #22725] is this a bug?

# New Ticket Created by "Marie Vivian Wong Tzu Yenn"
# Please include the string​: [perl #22725]
# in the subject line of all future correspondence about this issue.
# <URL​: http​://rt.perl.org/rt2/Ticket/Display.html?id=22725 >

Hi there,

I'm new to perl and was writing a small program. Found something funny.
When I try to add this particular sequence of numbers (0.4+0.3+0.2+0.1),
it does not add up to one. (falls to the else loop).
The version of perl compiler I am using is perl 5.6.1 on windows and
solaris

If I change these numbers to like 0.25+0.5+0.25 OR 0.9+0.1 etc then no
problem.

Here is the code snippet​:

*************************
use strict;
use warnings;

my $tmp = 0.4+0.3+0.2+0.1;
if ($tmp == 1) {
  print "Equals one", "\n";
}
else {
  print "Not equal to one", "\n";
}
exit;

thanks!
Marie
email​: marie_wong@​gmx.net


This e-mail and any attachments may contain confidential and/or
privileged material; it is for the intended addressee(s) only.
If you are not a named addressee, you must not use, retain or
disclose such information.

NPL Management Ltd cannot guarantee that the e-mail or any
attachments are free from viruses.

NPL Management Ltd. Registered in England and Wales. No​: 2937881
Registered Office​: Teddington, Middlesex, United Kingdom TW11 0LW.


@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From @demerphq

of numbers (0.4+0.3+0.2+0.1), it does not add up to one.
(falls to the else loop).
...
If I change these numbers to like 0.25+0.5+0.25 OR 0.9+0.1
etc then no problem.

At first I thought this was a classic example of rounding problems. Assuming
that the binary representation of that sequence when summed doesnt actually
equal 1. As it would appear can be seen here​:

D​:\Development>perl -e "printf '%22.20f',0.4+0.3+0.2+0.1"
0.99999999999999989000

Whereas the binary representation of the other examples (0.9,0.1 and
0.25+0.25+0.5) do add up to 1​:

D​:\Development>perl -e "printf '%22.20f',0.25+0.5+0.25"
1.00000000000000000000
D​:\Development>perl -e "printf '%22.20f',0.9+0.1"
1.00000000000000000000

But the below makes me think that this is indeed a bug.

D​:\Development>perl -e "printf '%22.20f',0.4
0.40000000000000002000
D​:\Development>perl -e "printf '%22.20f',0.3
0.29999999999999999000
D​:\Development>perl -e "printf '%22.20f',0.2
0.20000000000000001000
D​:\Development>perl -e "printf '%22.20f',0.1
0.10000000000000001000

When I take these results and sum them in my handy dandy desk calculator I
get

1.00000000000000003

So now im not sure that this isnt a bug. But i dont know where it lies, or
to what degree we can trust the printf output.

However, the GOOD news is that your problem can be worked around by simply
using the string 'eq' and not the numerical ==.

D​:\Development>perl -e "print 0.4+0.3+0.2+0.1 == 1 ? 'Equals' : 'NotEquals'"
NotEquals
D​:\Development>perl -e "print 0.4+0.3+0.2+0.1 eq 1 ? 'Equals' : 'NotEquals'"
Equals

Ill leave it up to somebody else to determine if it is in fact a bug, and/or
what the cause of the discrepancy between the outputs.

Yves

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From Robin.Barker@npl.co.uk

I wrote​:

see C\<perldoc \-f decimal> for a full explanation\.

I meant​:
  perldoc -q decimal

Robin


This e-mail and any attachments may contain confidential and/or
privileged material; it is for the intended addressee(s) only.
If you are not a named addressee, you must not use, retain or
disclose such information.

NPL Management Ltd cannot guarantee that the e-mail or any
attachments are free from viruses.

NPL Management Ltd. Registered in England and Wales. No​: 2937881
Registered Office​: Teddington, Middlesex, United Kingdom TW11 0LW.


@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From @mhx

But the below makes me think that this is indeed a bug.

D​:\Development>perl -e "printf '%22.20f',0.4
0.40000000000000002000
D​:\Development>perl -e "printf '%22.20f',0.3
0.29999999999999999000
D​:\Development>perl -e "printf '%22.20f',0.2
0.20000000000000001000
D​:\Development>perl -e "printf '%22.20f',0.1
0.10000000000000001000

When I take these results and sum them in my handy dandy desk calculator I
get

1.00000000000000003

So now im not sure that this isnt a bug. But i dont know where it lies, or
to what degree we can trust the printf output.

Nope, no bug here. Just the classic rounding problem​:

  E​:\>type add.c
  #include <stdio.h>
  #include <stdlib.h>

  int main( int argc, char **argv )
  {
  double x = 0.0;
  while (--argc)
  x += atof( *++argv );
  printf("%22.20lf\n", x);
  }

  E​:\>.\add 0.4 0.3 0.2 0.1
  0.99999999999999989000

  E​:\>perl -e"printf qq'%22.20f\n', 0.4+0.3+0.2+0.1"
  0.99999999999999989000

Remember, the precision of a "double" mantissa is only
53 bits, i.e. about 1e-16​:

  0.00000 00000 00000 1
  0.99999 99999 99999 89000

So the error is quite ok after 3 floating point operations.

However, the easiest workaround is obviously to just write
the operands in the correct order​:

  E​:\>perl -e"printf qq'%22.20f\n', 0.4+0.2+0.1+0.3"
  1.00000000000000000000

;-)

-- Marcus

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From @mhx

RE​: [perl #22725] is this a bug?> > Remember, the precision of a "double" mantissa is only

53 bits, i.e. about 1e-16​:

0.00000 00000 00000 1
0.99999 99999 99999 89000

So the error is quite ok after 3 floating point operations.

Ok, im still confused. Is the mantissa responsible for the difference in these​:

    C&#8203;:\\>type addnums\.cpp 
    // AddNums\.cpp : Defines the entry point for the console application\. 
    // 
    
    \#include "stdafx\.h" 
    \#include \<stdio\.h> 
    \#include \<stdlib\.h> 
    
    int \_tmain\(int argc\, \_TCHAR\* argv\[\]\) 
    \{ 
    
        double x = 0\.0; 
    
            while \(\-\-argc\) \{ 
                    double val = atof\( \*\+\+argv \); 
                    x \+= val; 
                    printf\("Add  : %22\.20lf\\tSum  :%22\.20lf\\n"\, val\,x\); 
            \} 
            printf\("Final&#8203;: %22\.20lf\\n"\, x\); 
    \} 
    
    C&#8203;:\\>addnums 0\.1 0\.2 0\.3 0\.4 
    Add  : 0\.10000000000000001000   Sum  :0\.10000000000000001000 
    Add  : 0\.20000000000000001000   Sum  :0\.30000000000000004000 
    Add  : 0\.29999999999999999000   Sum  :0\.60000000000000009000 
    Add  : 0\.40000000000000002000   Sum  :1\.00000000000000000000 
    Final&#8203;: 1\.00000000000000000000 
    
    C&#8203;:\\>addnums 0\.4 0\.3 0\.2 0\.1 
    Add  : 0\.40000000000000002000   Sum  :0\.40000000000000002000 
    Add  : 0\.29999999999999999000   Sum  :0\.69999999999999996000 
    Add  : 0\.20000000000000001000   Sum  :0\.89999999999999991000 
    Add  : 0\.10000000000000001000   Sum  :0\.99999999999999989000 
    Final&#8203;: 0\.99999999999999989000 

Yes.

  E​:\>type float.pl
  $a = 1.0e-16;
  $b = 0.0;
 
  $b += $a for 1 .. 100000;
  $b += 1.0;
 
  printf "%22.20f\n", $b;
 
  $b = 1.0;
  $b += $a for 1 .. 100000;
 
  printf "%22.20f\n", $b;
 
  E​:\>perl float.pl
  1.00000000001000000000
  1.00000000000000000000

As you can see, initializing $b to zero and adding 1e-16 for 100000
times can be done quite exact in IEEE math. It's because the numbers
are all just about the same magnitude. It does not matter if you're
dealing with numbers between 1 and 1000 or between 1e-100 and 1e-103.
But adding 1 and 1e-100 is impossible.

That's what the second example shows​: initializing $b to one and
adding 1e-16 for 100000 times has no effect at all. Just because
1.0000000000000001 cannot be represented by a double precision float.

And thanks for the follow up, I appreciate it.

BTW, the above makes me think that its safer to sum floats inorder. Would this be correct?

Although I'm not an expert (so don't blame me if I'm wrong ;-) I'd
say that adding floats should be more precise when you're doing it
in ascending order of the absolute values.

-- Marcus

Yves

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From @pjcj

Orton, Yves said​:

D​:\Development>perl -e "print 0.4+0.3+0.2+0.1 == 1 ? 'Equals' :
'NotEquals'"
NotEquals

Ill leave it up to somebody else to determine if it is in fact a bug,
and/or what the cause of the discrepancy between the outputs.

Here's a patch for the bug​:

*** pp_hot.c.org Thu Jul 18 23​:32​:07 2002
--- pp_hot.c Wed Jun 18 17​:04​:43 2003
***************
*** 287,292 ****
--- 287,295 ----
  #endif
  {
  dPOPnv;
+ if (ckWARN(WARN_NUMERIC))
+ Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
+ "Comparing equality of floating point values");
  SETs(boolSV(TOPn == value));
  RETURN;
  }

*** pp.c.org Tue Jun 18 22​:26​:49 2002
--- pp.c Wed Jun 18 17​:09​:17 2003
***************
*** 1953,1958 ****
--- 1953,1961 ----
  #endif
  {
  dPOPnv;
+ if (ckWARN(WARN_NUMERIC))
+ Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
+ "Comparing equality of floating point values");
  SETs(boolSV(TOPn != value));
  RETURN;
  }

./perl -we "print 0.4+0.3+0.2+0.1 == 1 ? 'Equals' : 'NotEquals'"
Comparing equality of floating point values at -e line 1.
NotEquals

--
Paul Johnson - paul@​pjcj.net
http​://www.pjcj.net

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From perl5-porters@ton.iguana.be

In article <18286.193.134.254.145.1055950103.squirrel@​wesley.pjcj.net>,
  "Paul Johnson" <paul@​pjcj.net> writes​:

Orton, Yves said​:

D​:\Development>perl -e "print 0.4+0.3+0.2+0.1 == 1 ? 'Equals' :
'NotEquals'"
NotEquals

Ill leave it up to somebody else to determine if it is in fact a bug,
and/or what the cause of the discrepancy between the outputs.

Here's a patch for the bug​:

*** pp_hot.c.org Thu Jul 18 23​:32​:07 2002
--- pp_hot.c Wed Jun 18 17​:04​:43 2003
***************
*** 287,292 ****
--- 287,295 ----
#endif
{
dPOPnv;
+ if (ckWARN(WARN_NUMERIC))
+ Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
+ "Comparing equality of floating point values");
SETs(boolSV(TOPn == value));
RETURN;

No. That would be a cure worse than the disease. Many floating point
operations are 100% predictabl and it can be perfectly ok to use ==
on them, e.g​:

perl -wle '$a=2.; print "yes" if $a+3. == 5.'

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From @demerphq

Here's a patch for the bug​:

./perl -we "print 0.4+0.3+0.2+0.1 == 1 ? 'Equals' : 'NotEquals'"
Comparing equality of floating point values at -e line 1.
NotEquals

Nice!

Yves

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

@rspier - Status changed from 'new' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

From @pjcj

On Wed, Jun 18, 2003 at 04​:25​:45PM +0000, Ton Hospel wrote​:

In article <18286.193.134.254.145.1055950103.squirrel@​wesley.pjcj.net>,
"Paul Johnson" <paul@​pjcj.net> writes​:

Orton, Yves said​:

D​:\Development>perl -e "print 0.4+0.3+0.2+0.1 == 1 ? 'Equals' :
'NotEquals'"
NotEquals

Ill leave it up to somebody else to determine if it is in fact a bug,
and/or what the cause of the discrepancy between the outputs.

Here's a patch for the bug​:

*** pp_hot.c.org Thu Jul 18 23​:32​:07 2002
--- pp_hot.c Wed Jun 18 17​:04​:43 2003
***************
*** 287,292 ****
--- 287,295 ----
#endif
{
dPOPnv;
+ if (ckWARN(WARN_NUMERIC))
+ Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
+ "Comparing equality of floating point values");
SETs(boolSV(TOPn == value));
RETURN;

No. That would be a cure worse than the disease. Many floating point

In case anyone was unsure, the patch was not meant to be applied.

operations are 100% predictabl and it can be perfectly ok to use ==
on them, e.g​:

perl -wle '$a=2.; print "yes" if $a+3. == 5.'

However, this case would not have triggered the warning​:

./perl -wle '$a=2.; print "yes" if $a+3. == 5.'
yes

./perl -wle '$a=2.1; print "yes" if $a+3.1 == 5.2'
Comparing equality of floating point values at -e line 1.
yes

--
Paul Johnson - paul@​pjcj.net
http​://www.pjcj.net

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2003

@rgs - Status changed from 'open' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Jun 19, 2003

From nick.ing-simmons@elixent.com

Marie Vivian Wong Tzu Yenn <perl5-porters@​perl.org> writes​:

# New Ticket Created by "Marie Vivian Wong Tzu Yenn" Please include the
# string​: [perl #22725] in the subject line of all future correspondence about
# this issue. <URL​: http​://rt.perl.org/rt2/Ticket/Display.html?id=22725 >

Hi there,

I'm new to perl and was writing a small program. Found something funny. When I
try to add this particular sequence of numbers (0.4+0.3+0.2+0.1), it does not
add up to one. (falls to the else loop). The version of perl compiler I am
using is perl 5.6.1 on windows and solaris

This isn't a perl problem it is a generic floating point problem common
to all computers and languages.

The problem is that just as you cannot represent 1/6 or 1/3 as an exact
decimal form, computers cannot represent 0.1 (1/10) as an exact binary
form. So this fails for same reason 0.333 + 0.333 + 0.333 != 1

If I change these numbers to like 0.25+0.5+0.25 OR 0.9+0.1 etc then no
problem.

0.25 and 0.5 are exact in binary. 0.9 and 0.1 are like 0.667 + 0.333
and happen to work.

--
Nick Ing-Simmons http​://www.ni-s.u-net.com/

@p5pRT
Copy link
Author

p5pRT commented Jul 6, 2003

From acme@astray.com

Very amusing discussion but not a bug.

@p5pRT
Copy link
Author

p5pRT commented Jul 6, 2003

acme@astray.com - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant