Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.85k stars 527 forks source link

Floating Point Number Printing Bug #1174

Closed p5pRT closed 20 years ago

p5pRT commented 24 years ago

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

Searchable as RT2143$

p5pRT commented 24 years ago

From pdh@best.com

Created by pdh@best.com

Hi\,

This is an obscure bug. A number is reported as being precisely 25\, but when int() is applied\, it is changed to 24. No doubt the number is something like 24.99999999999 and print() is somehow falsely reporting it as 25. (See below).

I've been using perl for years without ever really finding a bug\, so this is quite exciting!

Peter pdh@​best.com

Case 1​: Works perl -e 'print exp( (1 / 2) * log(625) )\, "\n"' 25

Case 2​: Take integer part\, doesn't work​: perl -e 'print int(exp( (1 / 2) * log(625) ))\, "\n"' 24

Case 3​: Add small constant\, works again​: perl -e 'print int(exp( (1 / 2) * log(625) ) + .0000001)\, "\n"' 25

Perl Info ``` Site configuration information for perl 5.00404: Configured by pdh at Sat Dec 25 13:02:06 PST 1999. Summary of my perl5 (5.0 patchlevel 4 subversion 4) configuration: Platform: osname=netbsd, osvers=1.4.1, archname=i386-netbsd uname='netbsd natasha 1.4.1 netbsd 1.4.1 (generic) #0: thu dec 23 09:54:05 pst 1999 pdh@natasha:usrsrcsysarchi386compilegeneric i386 ' hint=recommended, useposix=true, d_sigaction=define bincompat3=y useperlio=undef d_sfio=undef Compiler: cc='cc', optimize='-O2', gccversion=egcs-2.91.60 19981201 (egcs-1.1.1 release) cppflags='-I/usr/pkg/include' ccflags ='-I/usr/pkg/include' stdchar='char', d_stdstdio=undef, usevfork=true voidflags=15, castflags=0, d_casti32=define, d_castneg=define intsize=4, alignbytes=4, usemymalloc=n, prototype=define Linker and Libraries: ld='ld', ldflags =' -L/usr/pkg/lib' libpth=/usr/pkg/lib /usr/lib libs=-lm -lcrypt libc=/usr/lib/libc.so.12.40, so=so useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=define, ccdlflags='-Wl,-R/usr/pkg/lib -Wl,-R/usr/pkg/lib/perl5/i386-netbsd/5.00404/CORE' cccdlflags='-DPIC -fPIC ', lddlflags='-Bforcearchive -Bshareable -L/usr/pkg/lib' Locally applied patches: @INC for perl 5.00404: /usr/pkg/lib/perl5/i386-netbsd/5.00404 /usr/pkg/lib/perl5 /usr/pkg/lib/perl5/site_perl/i386-netbsd /usr/pkg/lib/perl5/site_perl . Environment for perl 5.00404: HOME=/usr/home/pdh LANG (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/usr/bin:/bin:/usr/pkg/bin:/usr/local/bin:/usr/home/pdh/bin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/pkg/sbin:/usr/pkg/bin:/usr/X11R6/bin:/usr/local/sbin:/usr/local/bin PERL_BADLANG (unset) SHELL=/usr/pkg/bin/bash ```
p5pRT commented 24 years ago

From @tamias

On Sun\, Feb 13\, 2000 at 03​:50​:27PM -0800\, Peter Hendrickson wrote​:

This is a bug report for perl from pdh@​best.com\, generated with the help of perlbug 1.20 running under perl 5.00404.

----------------------------------------------------------------- [Please enter your report here] Hi\,

This is an obscure bug. A number is reported as being precisely 25\, but when int() is applied\, it is changed to 24. No doubt the number is something like 24.99999999999 and print() is somehow falsely reporting it as 25. (See below).

I've been using perl for years without ever really finding a bug\, so this is quite exciting!

I'm afraid this bug is neither as obscure nor as exciting as you think.

perldoc -q decimal (or perldoc perlfaq4 with perl5.004_04)

=head2 Why am I getting long decimals (eg\, 19.9499999999999) instead of the numbers I should be getting (eg\, 19.95)?

Ronald

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Created by pdh@best.com

Hi\,

This is an obscure bug. A number is reported as being precisely 25\, but when int() is applied\, it is changed to 24. No doubt the number is something like 24.99999999999 and print() is somehow falsely reporting it as 25. (See below).

I've been using perl for years without ever really finding a bug\, so this is quite exciting!

I'm afraid this bug is neither as obscure nor as exciting as you think.

perldoc -q decimal (or perldoc perlfaq4 with perl5.004_04)

=head2 Why am I getting long decimals (eg\, 19.9499999999999) instead of the numbers I should be getting (eg\, 19.95)?

I believe you have misunderstood the bug. The problem is that I am *not* getting a long decimal. That is\, a number is reported by print() to be "25"\, but when int() is applied you get 24.

If I was getting something like "24.9999999999999..." I would be happy because that would make sense. It doesn't make sense to report "25" if the number is going to behave like "24.9999999999999...".

Here's another symptom. This should not happen​:

perl -e 'print 10000000000000 * exp( (1 / 2) * log(625) )\, "\n";' 250000000000000

perl -e 'print int(10000000000000 * exp( (1 / 2) * log(625)) )\, "\n";' 249999999999999

Peter pdh@​best.com

P.S. Here's the original bug report​: -------------------------------------------------- From pdh Sun Feb 13 15​:50​:11 -0800 2000 From​: Peter Hendrickson \pdh@​best\.com To​: perlbug@​perl.com Subject​: Floating Point Number Printing Bug

This is a bug report for perl from pdh@​best.com\, generated with the help of perlbug 1.20 running under perl 5.00404.

----------------------------------------------------------------- [Please enter your report here] Hi\,

This is an obscure bug. A number is reported as being precisely 25\, but when int() is applied\, it is changed to 24. No doubt the number is something like 24.99999999999 and print() is somehow falsely reporting it as 25. (See below).

I've been using perl for years without ever really finding a bug\, so this is quite exciting!

Peter pdh@​best.com

Case 1​: Works perl -e 'print exp( (1 / 2) * log(625) )\, "\n"' 25

Case 2​: Take integer part\, doesn't work​: perl -e 'print int(exp( (1 / 2) * log(625) ))\, "\n"' 24

Case 3​: Add small constant\, works again​: perl -e 'print int(exp( (1 / 2) * log(625) ) + .0000001)\, "\n"' 25

Perl Info ``` Site configuration information for perl 5.00404: Configured by pdh at Sat Dec 25 13:02:06 PST 1999. Summary of my perl5 (5.0 patchlevel 4 subversion 4) configuration: Platform: osname=netbsd, osvers=1.4.1, archname=i386-netbsd uname='netbsd natasha 1.4.1 netbsd 1.4.1 (generic) #0: thu dec 23 09:54:05 pst 1999 pdh@natasha:usrsrcsysarchi386compilegeneric i386 ' hint=recommended, useposix=true, d_sigaction=define bincompat3=y useperlio=undef d_sfio=undef Compiler: cc='cc', optimize='-O2', gccversion=egcs-2.91.60 19981201 (egcs-1.1.1 release) cppflags='-I/usr/pkg/include' ccflags ='-I/usr/pkg/include' stdchar='char', d_stdstdio=undef, usevfork=true voidflags=15, castflags=0, d_casti32=define, d_castneg=define intsize=4, alignbytes=4, usemymalloc=n, prototype=define Linker and Libraries: ld='ld', ldflags =' -L/usr/pkg/lib' libpth=/usr/pkg/lib /usr/lib libs=-lm -lcrypt libc=/usr/lib/libc.so.12.40, so=so useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=define, ccdlflags='-Wl,-R/usr/pkg/lib -Wl,-R/usr/pkg/lib/perl5/i386-netbsd/5.00404/CORE' cccdlflags='-DPIC -fPIC ', lddlflags='-Bforcearchive -Bshareable -L/usr/pkg/lib' Locally applied patches: @INC for perl 5.00404: /usr/pkg/lib/perl5/i386-netbsd/5.00404 /usr/pkg/lib/perl5 /usr/pkg/lib/perl5/site_perl/i386-netbsd /usr/pkg/lib/perl5/site_perl . Environment for perl 5.00404: HOME=/usr/home/pdh LANG (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/usr/bin:/bin:/usr/pkg/bin:/usr/local/bin:/usr/home/pdh/bin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/pkg/sbin:/usr/pkg/bin:/usr/X11R6/bin:/usr/local/sbin:/usr/local/bin PERL_BADLANG (unset) SHELL=/usr/pkg/bin/bash ```
p5pRT commented 24 years ago

From @tamias

On Mon\, Feb 14\, 2000 at 02​:03​:32PM -0800\, Peter Hendrickson wrote​:

I'm afraid this bug is neither as obscure nor as exciting as you think.

perldoc -q decimal (or perldoc perlfaq4 with perl5.004_04)

=head2 Why am I getting long decimals (eg\, 19.9499999999999) instead of the numbers I should be getting (eg\, 19.95)?

I believe you have misunderstood the bug. The problem is that I am *not* getting a long decimal. That is\, a number is reported by print() to be "25"\, but when int() is applied you get 24.

If I was getting something like "24.9999999999999..." I would be happy because that would make sense. It doesn't make sense to report "25" if the number is going to behave like "24.9999999999999...".

It's all the same 'bug'. print() uses a format for printing floating point numbers that rounds the number to a certain position past the decimal point. (That position depends on your system and the version of Perl.) See the documentation for $# in perlvar. (It's depecrated\, but explains how print works with floating point numbers.)

int()\, on the other hand\, does not round the number before truncating it.

Try replacing your print with printf "%.16f".

Ronald

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Peter Hendrickson \pdh@​best\.com wrote

From​: Ronald J Kimball \rjk@​linguist\.dartmouth\.edu

I'm afraid this bug is neither as obscure nor as exciting as you think.

perldoc -q decimal (or perldoc perlfaq4 with perl5.004_04)

=head2 Why am I getting long decimals (eg\, 19.9499999999999) instead of the numbers I should be getting (eg\, 19.95)?

I believe you have misunderstood the bug. The problem is that I am *not* getting a long decimal. That is\, a number is reported by print() to be "25"\, but when int() is applied you get 24.

No. Ronald understands floating point very well. You have failed to understand the import of the FAQ which he quoted. But you are not alone\, so in current versions(*) of Perl\, the entry for int() has been extended​:

% perldoc -f int =item int EXPR

=item int

Returns the integer portion of EXPR. If EXPR is omitted\, uses C\<$_>. You should not use this function for rounding​: one because it truncates towards C\<0>\, and two because machine representations of floating point numbers can sometimes produce counterintuitive results. For example\, C\<int(-6.725/0.025)> produces -268 rather than the correct -269; that's because it's really more like -268.99999999999994315658 instead. Usually\, the C\<sprintf()>\, C\<printf()>\, or the C\<POSIX​::floor> and C\<POSIX​::ceil> functions will serve you better than will int().

(*) I note you are using a Perl version which is two and a half years   out of date; you might wish to consider upgrading. The   documentation isn't the only thing which has been improved.

Mike Guy

p5pRT commented 24 years ago

From @tamias

On Tue\, Feb 15\, 2000 at 06​:38​:37PM +0000\, M.J.T. Guy wrote​:

Peter Hendrickson \pdh@&#8203;best\.com wrote

I believe you have misunderstood the bug. The problem is that I am *not* getting a long decimal. That is\, a number is reported by print() to be "25"\, but when int() is applied you get 24.

No. Ronald understands floating point very well. You have failed to understand the import of the FAQ which he quoted. But you are not alone\, so in current versions(*) of Perl\, the entry for int() has been extended​:

FYI for p5p​: Peter emailed me offlist acknowledging that he understands the issue now.

Ronald