Still can only access the forum from my mobile, so let's try it via mobile
Thaddy: Agreed that chacha20 would be the professional solution. But I think the OP has fun in designing his own algorithm. I sympathise with that, it is less productive than using a library but forces one to think and better understand the problems and pitfalls.
@ad1mt: Not the CMWC4096 "mother of all", just a basic lag1 MWC. Below a simple example, fixed seed, and for real use I would pack the generator into an advanced record.
I also attached a function to test or suitable multipliers that satisfy Prof. Marsaglias condition. It needs the GMP library which comes packed with FPC. I think it is correct.
uses gmp; //library is required for function MPZIsSafePrime() only
{$R-,Q-}
function MWC32r1: dword;
{Basic MWC lag-1 generator
High quality random numbers based on Multiply With Carry, by Prof. Marsaglia
x(n)=a*x(n-1)+carry mod 2^32. Period is a*2^31-1. Multiplier (any one will do):
1791398085 1683268614 1965537969 1675393560 1967773755 1517746329 1447497129 1655692410 1606218150
2051013963 1075433238 1557985959 1781943330 1893513180 1631296680 2131995753 2083801278 1873196400 1554115554
or any a for which both a*2^32-1 and a*2^31-1 are prime
}
var t: qword ;
const A: dword = 23;
B: dword = 12318; //Mind the conditions; A and B shall not be both zero, and not equal multiplier-1;
//not sure -> consult wikipedia
begin
t := qword (2131995753)*A+B;
A := lo(t);
B := hi(t);
result := A;
end;
function MPZIsSafePrime (const a, b,r: dword): boolean;
{decides whether for a given multiplier a the terms p=a*b^r-1 and (p-1)/2 = (a*b^r/2-1) are both prime.
In other words, if p = a*(2^32)-1 is a "safe prime".
b is in bits e.g. 32, r is the lag}
var a1,b1,p,one,two: mpz_t;
begin
mpz_init (a1);
mpz_init (b1);
mpz_init (p);
mpz_set_ui(a1,a);
mpz_ui_pow_ui(b1,2,b*r); //b1 = 2^(b*r)
mpz_mul (p, a1,b1);
mpz_sub_ui (p, p, 1);
result := mpz_probab_prime_p (p,15) > 0;
//nun testen wir noch (p-1)/2 = a*b^r/2-1.
mpz_ui_pow_ui(b1,2,b*r-1);
mpz_mul (p, a1,b1); // p = a1*b1^r
mpz_sub_ui (p, p, 1);
result := result and (mpz_probab_prime_p (p,15) >0);
mpz_clear (p);
mpz_clear (b1);
mpz_clear (a1);
end;
var a,i: dword;
begin
writeln ('output 10 random values from MWC');
for i := 1 to 10 do writeln (MWC32r1);
writeln;
writeln ('calculate 10 suitable multipliers for 32 bit lag 1 MWC');
i := 0;
repeat
a := high (dword) div 4 * 3 + random (high (dword) div 4); //try some reasonably large number
if MPZIsSafePrime (a, 32, 1) then begin
writeln (a);
inc (i);
end;
until i>10;
end.
Edit: Thaddys version is from 16bit days, essentially it combines two 16-bit MCWs with different multiplier to one 32-bit generator. It is accordingly slow in comparison to a native 32bit Version.
But it is interesting to see that Prof Marsaglia combined two MCWs. That means as long as the multipliers are different, the streams are uncorrelated, otherwise the combined generator would be bad. In turn we may conclude that paralleling several 32bit MWCs is also ok.
On a side note - Marsaglias choice of multiplier (18000) was bad. While the 18000 satisfies his conditions, it causes correlations between subsequent words which can even be visualised in a randogram, which means it is really quite bad. I tested that earlier, and it is true for all even multipliers. So when calculating multipliers, avoid the even ones !