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

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

Thread Next
From:
Claus A. Andersen
Date:
November 29, 2000 13:34
Subject:
[ID 20001129.006] precision inconsistencies compromising >= and ==
Message ID:
200011292124.VAA2960549@genome.cbs.dtu.dk

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 Next


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