Reliable Computing, scripting language perspective
I am happy that I attended the Sun HPC Consortium Singapore 2006. This was held in conjunction with GridAsia 2006.
One of the presentations (Reliable Computing and Petascale systems, by Ruud van der Pas, Sun Microsystems)
interested me to explore further, from the viewpoint of scripting languages. Although his
presentation material is not available, I managed to find a similar paper that he presented last year in
Australia.
The Future Of Floating-Point Computing Is In Reliable Computing, in Australian Partnership for Advanced Computing Conference and Exhibition on Advanced Computing, Grid Applications and eResearch, 26-30 September 2005.
The equation in question is:
F(a,b) = (333.75-a^2)*b^6 + a^2*(11*a^2*b^2-121*b^4-2) + 5.5*b^8 + a/(2*b)
a = 77617.0; b = 33096.0
The answer (using 32-bit precision): 1.172604. Question: How Good Is This Result?
In thr APAC 2005 paper, it said:
"If we bump up the precision and the numbers match, we're okay" Not Necessarily .......
% ./rump.exe
Computed Results
32-bit precision: 1.172604
64-bit precision: 1.1726039400531786
128-bit precision: 1.1726039400531786949244406059733592
% ./rump.exe
Computed Results
32-bit precision: 1.172604
64-bit precision: 1.1726039400531786
128-bit precision: 1.1726039400531786949244406059733592
Correct Results
32-bit precision: -0.82739603
64-bit precision: -0.8273960599468213
128-bit precision: -0.8273960599468213050755593940266408
Okay, let's look at how scripting languages handle the above equation on my notebook running Cygwin:
Perl (5.8.7)
[ans=1.17260394005318] NOT CORRECT
$ cat rump.pl #! /usr/bin/perl $a=77617.0; $b=33096.0; $a2=$a*$a; $b2=$b*$b; $b4=$b2*$b2; $b6=$b4*$b2; $b8=$b6*$b2; $ans=(333.75-$a2)*$b6 + $a2*(11*$a2*$b2-121*$b4-2) + 5.5*$b8 + $a/(2*$b); print $ans; $ perl rump.pl 1.17260394005318
Tcl (8.4.1)
[ans=1.17260394005] NOT CORRECT
$ cat rump.tcl #! /usr/bin/tclsh proc f { a b } { set a2 [expr {$a*$a}] set b2 [expr {$b*$b}] set b4 [expr {$b2*$b2}] set b6 [expr {$b4*$b2}] set b8 [expr {$b6*$b2}] set ans [expr {(333.75-$a2)*$b6 + $a2*(11*$a2*$b2-121*$b4-2) + 5.5*$b8 + $a/(2*$b)}] return $ans } puts [f 77617.0 33096.0] $ ./rump.tcl 1.17260394005
Apparently all these calculations are based on IEEE floating point standard. If we were to calculate it long hand, it looks like this:
(333.75 - a^2)*b^6= -7917110903377385049079188237280149504.00 a^2*(11a^2*b^2-121*b^4-2)= -437291576312021946464244793346.00 5.5*b^8= 7917111340668961361101134701524942848.00 a/(2*b)= 1.17260394005317863185 ------------------------------------------------------------------------------- F(a,b)= -0.8273960599468213681411650954798162919991 -7917110903377385049079188237280149504.00 + -437291576312021946464244793346.00 + 7917111340668961361101134701524942848.00 = 2
Can we do it correctly with scripting languages (if we consider "bc" also) ? Let see
bc (1.06) [ANS=-.8273960599468213681411650954798162919991] CORRECT
$ cat rump.bc scale=40 a=77617.0 b=33096.0 (333.75-a^2)*b^6+a^2*(11*a^2*b^2-121*b^4-2)+5.5*b^8+a/(2*b) $ bc -l < rump.bc -.8273960599468213681411650954798162919991Perl (5.8.7) (same script as above, but run with Bignum module)
[ans=-0.827396059946821368141165095479816291999] CORRECT
$ cat rump.pl #! /usr/bin/perl $a=77617.0; $b=33096.0; $a2=$a*$a; $b2=$b*$b; $b4=$b2*$b2; $b6=$b4*$b2; $b8=$b6*$b2; $ans=(333.75-$a2)*$b6 + $a2*(11*$a2*$b2-121*$b4-2) + 5.5*$b8 + $a/(2*$b); print $ans; $ perl -Mbignum rump.pl -0.827396059946821368141165095479816291999Tcl (math::bigfloat)
[ans=-0.827396059946821368141165095479816291999] CORRECT
The tricky part is how much precision one has to set to get the correct answer. Also, the implementation is very clumsy.
package require math::bigfloat namespace import math::bigfloat::* set precision 77 set a [fromdouble 77617.0 $precision] set b [fromdouble 33096.0 $precision] set c333_75 [fromdouble 333.75 $precision] set c11 [fromdouble 11.0 $precision] set c121 [fromdouble 121.0 $precision] set c2 [fromdouble 2.0 $precision] set c5_5 [fromdouble 5.5 $precision] set a2 [mul $a $a] set b2 [mul $b $b] set b4 [mul $b2 $b2] set b6 [mul $b4 $b2] set b8 [mul $b6 $b2] set term1 [mul [sub $c333_75 $a2] $b6] set term2 [mul $a2 [sub [sub [mul [mul $c11 $a2] $b2] [mul $c121 $b4]] $c2]] set term3 [mul $c5_5 $b8] set term4 [div $a [mul $c2 $b]] set ans [add [add [add $term1 $term2] $term3] $term4] puts [tostr $ans]Tcl (Mpexpr)
[ans=-0.827396059946821368141165095479816291999] CORRECT
Tcl module (Mpexr ) is able to do multiple precision arithmatic. Below is Tcl 8.1.1 with Mpexr on Solaris, because I have problem compiling that with the latest Tcl8.4 on Cygwin
$ cat rump.tcl package require Mpexpr proc f { a b } { set a2 [mpexpr {$a*$a}] set b2 [mpexpr {$b*$b}] set b4 [mpexpr {$b2*$b2}] set b6 [mpexpr {$b4*$b2}] set b8 [mpexpr {$b6*$b2}] set ans [mpexpr {(333.75-$a2)*$b6 + $a2*(11*$a2*$b2-121*$b4-2) + 5.5*$b8 + $a/(2*$b)}] return $ans } set mp_precision 40 puts [f 77617.0 33096.0] $ tclsh rump.tcl -0.827396059946821368141165095479816291999
0 Comments:
Post a Comment
<< Home