The core of the algorithm is like this (W is the Sum of Ranks found in the test, N is the sample size):
my $NumberOfPossibilities = 2**$N; my $CountLarger = 0; for($i=0; $i < $NumberOfPossibilities; ++$i) { my $RankSum = 0; for($j=0; $j < $N; ++$j) { $RankSum += $j + 1 if(($i >> $j) & 1); }; ++$CountLarger if($RankSum >= $W); }; my $p = 2*$CountLarger / $NumberOfPossibilities;All 2**N possible distributions of of signs over ranks are generated as bit-patterns (i.e., just the integers from $i = 0 to $i = 2**N-1).
You might notice that (in C) the loop parameter i will be limited to a 32 bit integer on most platforms. This means that you cannot use this program for values of N >= 32. If you would care to calculate how long your computer will need to perform the 32*2**32 = 137438953472 ~ 1.4e11 inner loop runs you will not be worried (if your platform can perform these calculations fast enough, it will be 64-bit wide anyway).
Currently two implementations are available: in Perl and in
C.
The C version in much faster than the Perl version.
Numerical differences between the results from both implementations
stem from rounding differences and type conversions (both of which
are specific to C)
Note that neither program checks the input! Faulty input will
crash them.
These programs can be used and distributed freely. (copyright 1996, Rob van Son)