I have recently, Nov 3:
RNGs: A Super KISS, sci.math, comp.lang.c, sci.crypt.
developed a 32-bit KISS RNG with immense period, over 10^402575, great speed and excellent performance on tests of randomness. But it is not well-suited for extension to 64-bits or adaption to Fortran.
As 64-bit RNGs are becoming more in demand, I have modified that recently proposed 32-bit one to produce a 64-bit RNG with similar period, this time a mere 10^397524, but with instructions that should serve in diverse programming languages.
I list a C version below and ask for help from experts here on adapting it to a Fortran version.
The basic idea is that we add each term from three sequences, Congruential, Xorshift and CMWC (Complimentary-Multiply-With-Carry). For the latter, we merely take the next Q element, except if they have all been used, the Q array is refilled, the index reset and the first Q element returned. The refilling process should work for signed or unsigned integers, as should the Congruential and Xorshift elements. The CMWC process requires that we extract the top and bottom 64 bits of a supposed 128-bit t=a*x+c, without actually forming t, using only 64-bit operations.
The instructions, operations and assignments themselves all seem to have Fortran equivalents. The #include macros are merely sequences of assignments that can be transformed, and the Q() (nee Q[]) array must be accessible to all, which I would have done in the old days with common blocks.
Here is the C listing:
/* SUPRKISS64.c, period 52^1320480(2^64-1) */ #include <stdio.h> static unsigned long long Q[20632],carry=36243678541LL, xcng=12367890123456LL,xs=521288629546311LL,indx=20632;
#define CNG ( xcng=6906969069LL*xcng+123 ) #define XS ( xs^=xs<<13,xs^=xs>>17,xs^=xs<<43 ) #define SUPR ( indx<20632 ? Q[indx++] : refill() ) #define KISS SUPR+CNG+XS
unsigned long long refill( ) {int i; unsigned long long z,h; for(i=0;i<20635;i++){ h=(carry&1); z=((Q[i]<<41)>>1)+((Q[i]<<39)>>1)+(carry>>1); carry=(Q[i]>>23)+(Q[i]>>25)+(z>>63); Q[i]=~((z<<1)+h); } indx=1; return (Q[0]); }
int main() {int i; unsigned long long x; for(i=0;i<20632;i++) Q[i]=CNG+XS; for(i=0;i<1000000000;i++) x=KISS; printf('Does x=-5061657174865032461\n x=%LLd.\n',x); }
Given the initial seed values, a proper implementation of the mathematics behind the methods requires that the 10^9'th call return the 64-bit integer 13385086898844519155, which I have had printed as -5061657174865032461 for signed-integer implementations.
Can I count on any of you to provide a Fortran version?
George Marsaglia
Here is the 32-bit version of the above:
/* SUPRKISS32.c, period 52^1320481(2^32-1) */ #include <stdio.h> static unsigned long Q[41265],indx=41265, carry=362,xcng=1236789,xs=521288629;
#define CNG ( xcng=69609*xcng+123 ) /Congruential/ #define XS ( xs^=xs<<13,xs^=xs>>17,xs^=xs>>5 )/Xorshift/ #define SUPR ( indx<41265 ? Q[indx++] : refill() ) /CMWC/ #define KISS SUPR+CNG+XS
int refill( ) {int i; unsigned long z,h; for(i=0;i<41265;i++){ h=(carry&1); z=((Q[i]<<9)>>1)+((Q[i]<<7)>>1)+(carry>>1); carry=(Q[i]>>23)+(Q[i]>>25)+(z>>31); Q[i]=~((z<<1)+h); } indx=1; return (Q[0]); }
int main( ) {unsigned long i,x; for(i=0;i<41265;i++) Q[i]=CNG+XS; for(i=0;i<1000000000;i++) x=KISS; printf('Does x=1493864468?\n x=%d.\n',x); }