SPUG: S.O.S: Sum-Of-Squares (nickname:Help)

Itay Furman itayf at fhcrc.org
Wed Oct 1 18:05:00 CDT 2003


Hi,

I encountered a (literally) small numerical problem during a run of one of my 
scripts. I have written a small script that reproduces that behavior. It
accept as arguments the elements of a vector, calculates the sum-of-squares 
(sos), and then the normalized length of the vector (should be 1).
The output is the 'sos', and the deviation of the normalized length from 1, 
'residue'.
The problem: for some cases I get a small, non-zero deviation.
My question: does any one have some insight or rules-of-a-thumb as to 
the expected numerical precision in basic arithmetic operations under Perl?

I should point out that I have found a simple workaround (see further below), 
but would like some insight for future reference.

	Thanks,
	Itay

--

=========================================================================
Itay Furman
Fred Hutchinson Cancer Research Center		(206) 667-5921 (voice)
1100 Fairview Avenue N., Mailstop D4-100	(206) 667-2917 (fax)
P.O. Box 19024					
Seattle, WA  98109-1024				
=========================================================================


#### Here is my minimal script #####
$ cat test_innerprod.pl

#!/usr/local/bin/perl -w
use strict;
my @elem = @ARGV;               # Elements of vector.
my $sos  = 0;                   # Sum-Of-Squares
$sos    += $_**2 foreach (@elem);
print "\t"x4, "sos=$sos\tresidue=",
  1-$sos/($sos**0.5 * $sos**0.5), "\n";
exit;


#### Some examples ####

## OK
$ test_innerprod.pl 1 1 1 1
				sos=4   residue=0
$ test_innerprod.pl 1 0 0 0
				sos=1   residue=0
## Wrong !
$ test_innerprod.pl 1 1 1 0
				sos=3   residue=-2.22044604925031e-16
## Number of 1's doesn't matter, necessarily
$ test_innerprod.pl 1 1 0 0
				sos=2   residue=2.22044604925031e-16
## Order doesn't matter
$ test_innerprod.pl 1 0 1 0
				sos=2   residue=2.22044604925031e-16
## Length doesn't matter
$ test_innerprod.pl 1 1 0
				sos=2   residue=2.22044604925031e-16
## OK
$ test_innerprod.pl 1 0 0
				sos=1   residue=0
## Smallest vector that yields the flow
$ test_innerprod.pl 1 1
				sos=2   residue=2.22044604925031e-16
## These don't have to be 1's
$ test_innerprod.pl 0.5 0.5 0 0
                                sos=0.5 residue=2.22044604925031e-16
$ test_innerprod.pl 0.5 0.5
                                sos=0.5 residue=2.22044604925031e-16


#### My workaround ####

$ cat test_innerprod.pl
#!/usr/local/bin/perl -w
use strict;
my @elem = @ARGV;               # Elements of vector.
my $sos  = 0;                   # Sum-Of-Squares
$sos    += $_**2 foreach (@elem);
print "\t"x4, "sos=$sos\tresidue=",
  #################################################
  # Take the square-root AFTER making the product #
  # Compare with previous version                 #
  #   1-$sos/($sos**0.5 * $sos**0.5)              #
  #################################################
  1-$sos/($sos*$sos)**0.5, "\n";
exit;

## Were wrong before; now OK
$ test_innerprod.pl 1 1 1 0
				sos=3   residue=0
$ test_innerprod.pl 1 1 0 0
				sos=2   residue=0
$ test_innerprod.pl 1 1 0
				sos=2   residue=0
$ test_innerprod.pl 1 1
				sos=2   residue=0
$ test_innerprod.pl 0.5 0.5
                                sos=0.5 residue=0

#### End of message.




More information about the spug-list mailing list