Re: Found a sprintf() bug inPerl 5.6.1 (and mod_perl)
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)
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)
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)
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