I found a simple MWC random generator written in x86 assembly in an older thread of this forum, modified it a bit and and compared it to a Pascal version. Surprisingly, the Pascal code is just as fast or even faster than the assembler routine.
But, the output of the two routines is slightly different. When running both generators in parallel, their outputs will start to differ after a few calls. The difference is 1 at first, but then avalanches, of course.
Both versions reasonably pass the statistical tests I did, and should be good enough for my purpose. But, testing ten million numbers does not mean a lot, and I am a bit concerned that there may be a mistake in one of the generators which reduces its theoretical period length.
The asm code is very simple and I think it should do the same as the Pascal routine but it does not... guess it has to do with the handling of the carry bit. Does anyone have sufficient knowledge of assembler to tell where the difference is ?
{$mode objfpc}
{$asmmode intel}
{$OPTIMIZATION ON}
uses sysutils;
var T1: TDateTime;
function MWC: dword; inline;
var t : qword;
const c : dword = 100;
rngseed : dword = 100;
Multiplier : dword = 1791398085;
begin
t := qword (multiplier) * rngseed + c;
c := hi (t);
rngseed := lo(t);
result := lo(t);
end;
function MWC_ASM: dword; assembler; inline;
//FUNCTION AsmRand (rangw: dword): dword; pascal; assembler;
//returns integer 0..Range-1
{ High quality random numbers based on Multiply With Carry, by prof. Marsaglia
:: x(n)=a*x(n-1)+carry mod 2^32 ::
The period of the generator is a*2^31-1.
multiplier a can be selected from the following list (any one will do):
1791398085 1929682203 1683268614 1965537969 1675393560
1967773755 1517746329 1447497129 1655692410 1606218150
2051013963 1075433238 1557985959 1781943330 1893513180
1631296680 2131995753 2083801278 1873196400 1554115554}
const C : dword = 100;
RngSeed : dword = 100;
Multiplier : dword = 1791398085;
ASM
MOV EAX, rngseed
MUL Multiplier //64 bit multiplication, carry in EDX
ADD EAX, C //add previous carry
MOV RngSeed, EAX //update seed
MOV C, EDX //update carry, random number generation done
END;
const Num = 2000*100000;
var i,j: longint;
begin
writeln;
writeln ('Compare MWC : MWC_ASM');
for i := 1 to 10 do writeln (mwc:12,mwc_asm:12);
T1 := Now;
for i := num downto 0 do mwc;
writeln;
writeln ('------------- TIME MWC : ',(Now-T1)*3600*24*1e9/Num:3:3, ' ns. --------------------');
T1 := Now;
for j := num downto 0 do mwc_asm;
writeln;
writeln ('---------- TIME MWC_ASM : ',(Now-T1)*3600*24*1e9/Num:3:3, ' ns. --------------------');
end.