arisu писал(а):
просто поверил ей на слово, что это хороший генератор.
Для некриптографических целей у него хорошее качество, но вот использование в многопоточном режиме вызывает вопросы. Для многопоточности нужны всё же математические гарантии.
Кстати, на систему типов Оберона ещё хорошо ложатся LFSR/GFSR, единственная проблема - это скремблеры, т.е. выходные функции, они обычно сделаны для языков с целочисленным переполнением. Но если адаптировать скремблер AOX из ссылки [1] и классический генератор xoshiro128 из [2], то получается даже проще и быстрее моей модификации XKISS. Тестовое значение я взял из выдачи реализации на C99, проходящей TestU01, SmokeRand и PractRand (по меньшей мере до 8 ТиБ). AOX слабее ++ или **, но для большинства целей годится. Матрицу перехода для многопоточности можно взять из [2], мне ее лень было переписывать и тестировать:
Код:
(**
* 1. https://doi.org/10.1109/TC.2022.3204226
* 2. https://prng.di.unimi.it/
*)
MODULE xoshiro128aox;
IMPORT SYSTEM, Out;
TYPE Xoshiro128AoxState = RECORD
s : ARRAY 4 OF INTEGER;
END;
PROCEDURE Xoshiro128AoxInit(VAR obj : Xoshiro128AoxState;
s : ARRAY OF INTEGER);
VAR
i : INTEGER;
BEGIN
FOR i := 0 TO 3 DO
obj.s[i] := s[i]
END;
IF (obj.s[0] = 0) & (obj.s[1] = 0) & (obj.s[2] = 0) & (obj.s[3] = 0) THEN
obj.s[0] := 12345678; obj.s[1] := 87654321;
obj.s[2] := 22222222; obj.s[3] := 33333333
END
END Xoshiro128AoxInit;
PROCEDURE BitXor(a, b : INTEGER) : INTEGER;
BEGIN
RETURN SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, a) / SYSTEM.VAL(SET, b))
END BitXor;
PROCEDURE BitAnd(a, b : INTEGER) : INTEGER;
BEGIN
RETURN SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, a) * SYSTEM.VAL(SET, b))
END BitAnd;
PROCEDURE BitOr(a, b : INTEGER) : INTEGER;
BEGIN
RETURN SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, a) + SYSTEM.VAL(SET, b))
END BitOr;
PROCEDURE Xoshiro128AoxNext(VAR obj : Xoshiro128AoxState) : INTEGER;
VAR
sx, sa, out, t: INTEGER;
BEGIN
sx := BitXor(obj.s[0], obj.s[1]); sa := BitAnd(obj.s[0], obj.s[1]);
out := BitAnd(07FFFFFFFH, BitXor(sx, BitOr(ROR(sa, 31), ROR(sa, 30))));
t := LSL(obj.s[1], 9);
obj.s[2] := BitXor(obj.s[2], obj.s[0]);
obj.s[3] := BitXor(obj.s[3], obj.s[1]);
obj.s[1] := BitXor(obj.s[1], obj.s[2]);
obj.s[0] := BitXor(obj.s[0], obj.s[3]);
obj.s[2] := BitXor(obj.s[2], t);
obj.s[3] := ROR(obj.s[3], 21);
RETURN out
END Xoshiro128AoxNext;
PROCEDURE Xoshiro128AoxTest() : BOOLEAN;
CONST
uref = 0648D78B0H;
VAR
prng : Xoshiro128AoxState;
s : ARRAY 4 OF INTEGER;
i, u : INTEGER;
BEGIN
s[0] := 12345678; s[1] := 87654321; s[2] := 2; s[3] := 5;
u := 0;
Xoshiro128AoxInit(prng, s);
FOR i := 1 TO 100000 DO
u := Xoshiro128AoxNext(prng)
END;
Out.String("Output: "); Out.Int(u, 10); Out.Ln();
Out.String("Reference: "); Out.Int(uref, 10); Out.Ln();
FOR i := 1 TO 10 DO
Out.Int(Xoshiro128AoxNext(prng), 5);
Out.Ln()
END;
RETURN u = uref
END Xoshiro128AoxTest;
BEGIN
IF Xoshiro128AoxTest() THEN Out.String("Passed"); Out.Ln()
ELSE Out.String("Failed"); Out.Ln()
END
END xoshiro128aox.