develooper Front page | perl.perl5.porters | Postings from November 2000

Re: [ID 20001129.006] precision inconsistencies compromising >= and ==

Thread Previous
From:
John Peacock
Date:
November 30, 2000 06:24
Subject:
Re: [ID 20001129.006] precision inconsistencies compromising >= and ==
Message ID:
3A2662F7.C0C2057E@rowman.com
Claus - 

Please read "perldoc perlnumbers" for a detailed explanation.  The short
answer is that you are experiencing floating point notation errors, not
addition/subtraction errors.  This has nothing to do with Perl, but
rather the nature of floating point processing and binary notation.

If you are concerned about exact decimal math, you should use either
Math::BigFloat (which offers infinite precision decimals) or my own
module Math::FixedPrecision (which offers specified precision for 
applications where the data has limited precision, say 4 d.p.).  Both of
these modules currently suffer from performance issues, but I am working
with several other authors to improve that significantly.

One thing that you should also be aware of is that even if you use one
of these modules, but using printf("%30.28f \n",$weight{$hb}), you
forcing a conversion by the native c-library to a float (or double?)
which may well reintroduce the binary notation problems.  I actually
noticed, to my chagrin, that I fell subject to this exact problem in
my own module, so there should be a new version of M::FP on CPAN later
today.  8~(

HTH

John Peacock

p.s. This bug report should be closed

"Claus A. Andersen" wrote:
> 
> This is a bug report for perl from ca2@genome.cbs.dtu.dk,
> generated with the help of perlbug 1.20 running under perl 5.006.
> 
> Hi Perl experts !
> The precision of real numbers in a computer
> are naturally not infinite, but I have found
> that the >= and == operators are inconsistent
> with the default printout precission and are
> perform a comparison which is too close
> to the machine accuracy. When
> this is mixed with precision problems for
> numbers as large as 0.1, then I call it a
> bug.
> 
> Example:
> I found the bug while making a script, which I have
> shaved down. When performing ONLY 7 math operations
> where I add or subtract 0.01 I get a number with a
> precision error which compromises the == and >= operators.
> 
> #============== PERL code ==============================
> #! /usr/local/bin/perl
> 
> $\ = "\n"; # whenever print is used add a newline
> 
> # weight parameter init
> %weight = (
>   0.2  => 0.02,
>   0.25 => 0.10,
>   0.3  => 0.23,
>   0.4  => 0.17,
>   0.5  => 0.30,
>   0.6  => 0.07,
>   0.7  => 0.03,
>   0.8  => 0.02,
>   0.9  => 0.02,
>   1    => 0.03
> );
> 
> foreach $hb (sort {$a<=>$b} keys %weight){
>   push(@HBsample, $hb);
>   $NOhb++;
> }
> 
> #  perform the simple decent
> $score =10000;srand(19346738546);
> $oldscore = test();
> $hbINDEX  = 0;
> $hb = $HBsample[$hbINDEX];
> 
> while(1){
> 
>   # increase the weight
>   while(1){
>     $weight{$hb} += 0.01;$mathOPERATIONScounter[$hbINDEX]++;
>     $score = test(); # using the present weights
>     if($score<$oldscore){
>       $oldscore = $score;
>     }else{
>       $weight{$hb} -= 0.01;$mathOPERATIONScounter[$hbINDEX]++;
>       last;
>     }
>   }
> 
>   # decrease the weight
>   while(1){
> #  $weight{$hb}=0.01;
> printf("before weight = $weight{$hb}  weight = %30.28f \n",$weight{$hb});# if($weight{$hb} == 0.01);
>     if($weight{$hb} >= 0.01){  # assumption that 0.01 is the accuracy of the initial setting
>       $weight{$hb} -= 0.01;$mathOPERATIONScounter[$hbINDEX]++;
>     }else{
> print "$mathOPERATIONScounter[$hbINDEX] after perl precision $hb weight = $weight{$hb}";
> printf("$mathOPERATIONScounter[$hbINDEX] after high precision $hb weight = %30.28f \n",$weight{$hb});
>       last;
>     }
>     $score = test(); # using the present weights
>     if($score<$oldscore){
>       $oldscore = $score;
>     }else{
>       $weight{$hb} += 0.01; $mathOPERATIONScounter[$hbINDEX]++;
>       last;
>     }
>   }
> 
>   # try another
>   if(++$hbINDEX >= $NOhb){
>     $hbINDEX = 0;
>   }
>   $hb = $HBsample[$hbINDEX];
> }
> 
> sub test {
>   return(rand(2*$score));
> }
> 
> #====================OUTPUT from program ================================
> 
> ./PERLprecisionBUG.pl | head -30
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.1  weight = 0.1000000000000000055511151231
> before weight = 0.09  weight = 0.0900000000000000105471187339
> before weight = 0.23  weight = 0.2300000000000000099920072216
> before weight = 0.22  weight = 0.2200000000000000011102230246
> before weight = 0.21  weight = 0.2099999999999999922284388276
> before weight = 0.17  weight = 0.1700000000000000122124532709
> before weight = 0.16  weight = 0.1600000000000000033306690739
> before weight = 0.3  weight = 0.2999999999999999888977697537
> before weight = 0.07  weight = 0.0700000000000000066613381478
> before weight = 0.03  weight = 0.0299999999999999988897769754
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.03  weight = 0.0299999999999999988897769754
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.09  weight = 0.0900000000000000105471187339
> before weight = 0.21  weight = 0.2099999999999999922284388276
> before weight = 0.16  weight = 0.1600000000000000033306690739
> before weight = 0.3  weight = 0.2999999999999999888977697537
> before weight = 0.07  weight = 0.0700000000000000066613381478
> before weight = 0.03  weight = 0.0299999999999999988897769754
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.01  weight = 0.0099999999999999967387198652
> 7 after perl precision 0.9 weight = 0.01
> 7 after high precision 0.9 weight = 0.0099999999999999967387198652
> before weight = 0.03  weight = 0.0299999999999999988897769754
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.02  weight = 0.0199999999999999969468866823
> before weight = 0.09  weight = 0.0900000000000000105471187339
> 
> I have reproduced the same problem, but for much larger
> math operations counts:
>   perl -e '$a=2126;while($a>=0.01){$a-=0.01;}print "$a\n";'
>   1.53034494798643e-11
>   perl -e '$a=2127;while($a>=0.01){$a-=0.01;}print "$a\n";'
>   0.00999999999348068
> or for larger errors:
>   perl -e '$a=77101;while($a>=0.1){$a-=0.1;}print "$a\n";'
>   1.80026271667799e-11
>   perl -e '$a=77102;while($a>=0.1){$a-=0.1;}print "$a\n";'
>   0.0999999999598177
>   perl -e '$a=77102;while($a>=200){$a-=0.1;}print "$a\n";'
>   199.999999999953
> This does not seem to happen when working with integers in perl,
> so I guess perl 'smells' that they are integers.
> 
> I am using perl a lot and its a great language, so I'd like
> to thank you all for making it better.
> 
> Greetings
> Claus
> 
> ---
> This perlbug was built using Perl 5.00404 - Wed Dec  3 09:14:22 PST 1997
> It is being executed now by  Perl 5.006 - Fri Sep  8 13:10:32 MDT 2000.
> 
> Site configuration information for perl 5.006:
> 
> Configured by rlogin at Fri Sep  8 13:10:32 MDT 2000.
> 
> Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration:
>   Platform:
>     osname=irix, osvers=6.5, archname=IP25-irix
>     uname='irix64 genome 6.5 10181059 ip25 '
>     config_args='-de'
>     hint=recommended, useposix=true, d_sigaction=define
>     usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
>     useperlio=undef d_sfio=undef uselargefiles=define
>     use64bitint=undef use64bitall=undef uselongdouble=undef usesocks=undef
>   Compiler:
>     cc='cc -n32', optimize='-O3', gccversion=
>     cppflags='-D_BSD_TYPES -D_BSD_TIME -OPT:Olimit=0:space=ON -I/usr/local/include -DLANGUAGE_C'
>     ccflags ='-D_BSD_TYPES -D_BSD_TIME -woff 1009,1110,1174,1184,1552 -OPT:Olimit=0:space=ON -I/usr/local/include -DLANGUAGE_C'
>     stdchar='unsigned char', d_stdstdio=define, usevfork=false
>     intsize=4, longsize=4, ptrsize=4, doublesize=8
>     d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
>     ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
>     alignbytes=8, usemymalloc=n, prototype=define
>   Linker and Libraries:
>     ld='cc -n32', ldflags =' -L/usr/local/lib32 -L/usr/local/lib -Wl,-woff,84'
>     libpth=/usr/local/lib /usr/lib32 /lib32 /lib /usr/lib
>     libs=-ldb -lm -lc
>     libc=/usr/lib32/libc.so, so=so, useshrplib=false, libperl=libperl.a
>   Dynamic Linking:
>     dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags=' '
>     cccdlflags=' ', lddlflags='-n32 -shared -L/usr/local/lib32 -L/usr/local/lib'
> 
> Locally applied patches:
> 
> 
> ---
> @INC for perl 5.006:
>         /usr/local/lib/perl5/5.6.0/IP25-irix
>         /usr/local/lib/perl5/5.6.0
>         /usr/local/lib/perl5/site_perl/5.6.0/IP25-irix
>         /usr/local/lib/perl5/site_perl/5.6.0
>         /usr/local/lib/perl5/site_perl
>         .
> 
> ---
> Environment for perl 5.006:
>     HOME=/home/ochre/ca2
>     LANG (unset)
>     LD_LIBRARY_PATH=/usr/local/sw/rvplayer5.0
>     LOGDIR (unset)
>     PATH=/usr/sbin:/usr/bsd:/sbin:/usr/bin:/bin:/etc:/usr/etc:/usr/bin/X11:/usr/freeware/bin:/usr/cbs/bio/bin:/usr/cbs/bio/bin/irix64:/usr/local/bin64:/usr/local/bin:/usr/unic/bin:/usr/cbs/hacks/bin:/usr/local/sw/modeller4/bin:/home/ochre/ca2/bin/:/home/sheet/rapacki/projects/libwww-perl-0.40/libwww-perl-0.40/
>     PERL_BADLANG (unset)
>     SHELL=/bin/tcsh

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About