Re: Found a sprintf() bug inPerl 5.6.1 (and mod_perl)

2002-04-16 Thread Franck PORCHER

I think that if there is a bug, which i'm not convinced of (see below),
it's likely to be int(), which may *first* be called by sprintf to cast
the floating-point number into an integral format (%03d).

Indeed if you run :

perl -e '$a=0.57; print int($a * 100)'

you get 0.56 .


Now, there must be an explanation for such an interesting behavior!
It may even have to do with the binary representation of floating-point numbers(FPN)
using the IEEE format, where 32bits FPN are represented
using  23 bits of mantissa.

The following script shows that 0.57 (as an example), an many others,
cannot be represented using 23 bits mantissa :

# this find the negative powers of 2 that should be added together
# to reach the goal (eg 0.57)
perl -e '   $goal = $ARGV[0];
$negpw= 1;
l  = ();
$s  = 0;
foreach (1..23) {
$a = $a/2;
if ( ($s + $a) = $goal){
$s += $a;
push l, $_;
print(sprintf(%0.30f  -  %03d\n, $s, 
$s * 100 ))
}
};
print l
' 0.57

0.50  -  050
0.562500  -  056
0.5664062500  -  056
0.5683593750  -  056
0.5693359375  -  056
0.56982421875000  -  056
0.56994628906250  -  056
0.569976806640625000  -  056
0.569992065429687500  -  056
0.56694824218750  -  056
0.569332427978515625  -  056
1 4 8 9 10 11 13 15 16 17 22

i.e 0.1 + 0.0001 + 0.0001 + 0.1
+ ...

You see in the result that 0.57 *cannot be* represented
as an  exact sum of negative powers of 2 within
23 bits.

From there, I guess any thing that happens is OK.

The problem of floating point representation,
and all the dillies that go with iti, is in fact
as old as computer science itself!

To solve your problem, use :

print(sprintf(%2.0f\n, $a * 100 ))

Hope this helps.

Franck


On Mon, 15 Apr 2002, Dominique Blas wrote:

 Sorry,

 I've found the following bug in mod_perl 1.25 and Perl 5.6.1.
 Maybe was it already released  but in case not here it is :

 perl -e '
 $a=0.57;
 print sprintf(%03d, $a * 100)'

 prints 056 instead of 057

 Same behaviour with $a=0,58 that prints 057.

 Of course it works for other values and also if you write

 $a=0,57*100;
 print sprintf(%03d, $a);


 Bug in sprintf() ?


 Sincerely,

 db


-- 

Bonne réception,

Franck


Essential Software - Ingénierie Informatique
Solutions Linux  Open Source en Polynésie française

http://www.esoft.pf/
Tél: (689) 56 23 95





Re: Found a sprintf() bug inPerl 5.6.1 (and mod_perl)

2002-04-15 Thread Stas Bekman

Dominique Blas wrote:
 Sorry,
 
 I've found the following bug in mod_perl 1.25 and Perl 5.6.1.
 Maybe was it already released  but in case not here it is :
 
 perl -e '
 $a=0.57;
 print sprintf(%03d, $a * 100)'
 
 prints 056 instead of 057
 
 Same behaviour with $a=0,58 that prints 057.
 
 Of course it works for other values and also if you write 
 
 $a=0,57*100;
 print sprintf(%03d, $a);
 
 
 Bug in sprintf() ?

No, this is not a bug. %d is the same as int(). Consider:

% perl -le '$a=0.57; print int ($a*100)'
56

Now read the manpage:

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

this explains the problem.

__
Stas BekmanJAm_pH -- Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide --- http://perl.apache.org
mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com




Re: Found a sprintf() bug inPerl 5.6.1 (and mod_perl)

2002-04-15 Thread Andy Lester

 correct -269; that's because it's really more like
 -268.94315658 instead.  Usually, the
 sprintf, printf, or the POSIX::floor and

And in this case, that means:

alester@flr4[~/play]$ more sprintf.pl
#!/usr/bin/perl -w

$a=0.57 * 100;
print sprintf(%03d %20.19f\n, $a,$a);


alester@flr4[~/play]$ perl sprintf.pl
056 56.9928946

...

In general, the chances that you've found a bug in the language or
implementation that's been around as long and is as widely used as Perl
5.6 is preeetty small.

#!Andy


-- 
'Andy Lester[EMAIL PROTECTED]
 Programmer/author  petdance.com
 Daddy  parsley.org/quinn   Jk'=~/.+/s;print((split//,$)
[unpack'C*',n2]3%+\34.'%.'^%4+!o.'])




Re: Found a sprintf() bug inPerl 5.6.1 (and mod_perl)

2002-04-15 Thread Dominique Blas

Thank you for your explanation both of you.

 alester@flr4[~/play]$ perl sprintf.pl
 056 56.9928946

 ...

 In general, the chances that you've found a bug in the language or
 implementation that's been around as long and is as widely used as Perl
 5.6 is preeetty small.

I know that !

That's why I didn't understand this behaviour first. Perl has been around  
 
since 13 years and during past years I've already found a few 
workarounds about bad calculations due to roundings.

I imagine that such a discussion occured in 80's.

But this one is different, behaviour is not equally distributed amongst
input values. I'm very puzzling with that.


I know that roundings are often tricky from language to language (Javascript 
has not the same rules for example and a small solid state calculator has 
different ones also).

But you must know that it's very difficult to write a portable code from 
langage to langage when rules are different.


And in Perl I found these rules not very consistent.


Can you tell me what you are thinking of that ?
^


perl -e '$a=0.79; printf sprintf(%03d %30.29f, $a*100, $a*100);'
079 79.0

perl -e '$a=0.69; printf sprintf(%03d %30.29f, $a*100, $a*100);'
069 69.0

perl -e '$a=0.49; printf sprintf(%03d %30.29f, $a*100, $a*100);'
049 49.0

perl -e '$a=0.55; printf sprintf(%03d %30.29f, $a*100, $a*100);'
055 55.00710542735760100

perl -e '$a=0.59; printf sprintf(%03d %30.29f, $a*100, $a*100);'
059 59.0

perl -e '$a=0.56; printf sprintf(%03d %30.29f, $a*100, $a*100);'
056 56.00710542735760100

perl -e '$a=0.61; printf sprintf(%03d %30.29f, $a*100, $a*100);'
061 61.0

perl -e '$a=0.65; printf sprintf(%03d %30.29f, $a*100, $a*100);'
065 65.0

perl -e '$a=0.66; printf sprintf(%03d %30.29f, $a*100, $a*100);'
066 66.0

perl -e '$a=0.68; printf sprintf(%03d %30.29f, $a*100, $a*100);'
068 68.0

perl -e '$a=0.28; printf sprintf(%03d %30.29f, $a*100, $a*100);'
028 28.00355271367880050

perl -e '$a=0.27; printf sprintf(%03d %30.29f, $a*100, $a*100);'
027 27.0

perl -e '$a=0.26; printf sprintf(%03d %30.29f, $a*100, $a*100);'
026 26.0

perl -e '$a=0.24; printf sprintf(%03d %30.29f, $a*100, $a*100);'
024 24.0

perl -e '$a=0.47; printf sprintf(%03d %30.29f, $a*100, $a*100);'
047 47.0

perl -e '$a=0.33; printf sprintf(%03d %30.29f, $a*100, $a*100);'
033 33.0

perl -e '$a=0.17; printf sprintf(%03d %30.29f, $a*100, $a*100);'
017 17.0

And if you try a loop, it works too, since, for perl, 0.01+0.01  0.02
and so on.


But if I take my calculator :
0.57*100 = 57 exactly !

Example :
perl -e 'for ($a=0.01;$a1;$a+=0.01) { print  sprintf(%20.19f %03d 
%20.19f\n, $a, $a*100, $a*100);} '
0.012 001 1.000
0.024 002 2.000
0.0299989 003 3.000
0.048 004 4.000
0.0500028 005 5.000
0.0600047 006 6.0008882
0.0700067 007 7.0008882
0.0800017 008 8.000
0.0899967 009 9.000
0.017 010 10.000
0.1099867 010 10.9982236
0.1199817 011 11.9982236
0.1299767 012 12.9982236
0.1399856 013 13.9982236
0.1499944 015 15.000
0.1600033 016 16.000
0.1700122 017 17.000
0.1800211 018 18.0035527
0.1900300 019 19.0035527
0.2000389 020 20.0035527
0.2100477 021 21.0035527
0.2200566 022 22.0071054
0.2300655 023 23.0071054
0.2400744 024 24.0071054
0.2500555 025 25.0071054
0.2600644 026 26.0071054
0.2700733 027 27.0071054
0.2800822 028 28.0071054
0.2900910 029 29.0106581
0.3000999 030 30.0106581
0.3101088 031 31.0106581
0.3201177 032 32.0142109
0.3301266 033 33.0142109
0.3401354 034 34.0142109
0.3501443 035 35.0142109
0.3601532 036 36.0142109
0.3701621 037 37.0142109
0.3801710 038