arisu писал(а):
зачем? чтобы иметь в зависимостях ещё и совершенно ненужный в этом случае сишный компилятор?
Если нужно передирать ассемблерные дампы из сишного компилятора, особенно нетривиальные, то зависимость от него на самом деле уже существует. И если понадобится перенести код под другую платформу, то без исходников на Си будет сложно.
Экспериментальный ГПСЧ без использования переполнений на Обероне-07 у меня сделать в итоге получилось, взяв за основу одну редкую модификацию комбинированного генератора KISS Марсальи. Он проходит TestU01 BigCrush, PractRand до 2 ТиБ включительно (может, и дальше пройдет, не знаю) и батареи SmokeRand. Период - около 2^83. Конструкция - комбинация LFSR и LCG (с простым делителем) с нелинейной выходной функцией. Алгоритм использует побитовые операции, но не целочисленные переполнения.
Код:
(**
* 1. https://doi.org/10.1214/aoap/1177005878
* 2. https://groups.google.com/g/comp.lang.fortran/c/5Bi8cFoYwPE
*)
MODULE xkiss;
IMPORT SYSTEM, Out;
TYPE XkissArState = RECORD
x : INTEGER;
a0, a1, c : INTEGER;
END;
PROCEDURE XkissArInit(VAR obj : XkissArState; x, a0, a1 : INTEGER);
BEGIN
obj.x := x;
obj.a0 := a0 MOD 67108863; (* 2^26 - 1 *)
obj.a1 := a1 MOD 67108863; (* 2^26 - 1 *)
obj.c := 1;
IF obj.x = 0 THEN obj.x := 123456 END;
IF obj.a0 < 0 THEN obj.a0 := 0 END;
IF obj.a1 < 0 THEN obj.a1 := 0 END
END XkissArInit;
PROCEDURE XkissArNext(VAR obj : XkissArState) : INTEGER;
CONST
mask26 = 03FFFFFFH;
mask31 = 07FFFFFFFH;
VAR
t: INTEGER;
BEGIN
(* LFSR part *)
obj.x := SYSTEM.VAL(INTEGER, (* x ^= x << 1 *)
SYSTEM.VAL(SET, obj.x) / SYSTEM.VAL(SET, LSL(obj.x, 1))
);
obj.x := SYSTEM.VAL(INTEGER, (* x ^= rotl32(x, 9) ^ rotl32(x, 27) *)
SYSTEM.VAL(SET, obj.x) / SYSTEM.VAL(SET, ROR(obj.x, 23)) /
SYSTEM.VAL(SET, ROR(obj.x, 5))
);
(* AWC part *)
t := obj.a0 + obj.a1 + obj.c;
obj.a1 := obj.a0;
obj.c := ASR(t, 26);
obj.a0 := SYSTEM.VAL(INTEGER,
SYSTEM.VAL(SET, t) * SYSTEM.VAL(SET, mask26)
);
(* Output function *)
RETURN SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, mask31) * (
SYSTEM.VAL(SET, obj.x) / SYSTEM.VAL(SET, LSL(obj.a0, 6)) /
SYSTEM.VAL(SET, obj.a1 * 29)
))
END XkissArNext;
PROCEDURE XkissArTest() : BOOLEAN;
CONST
uref = 0453EFE6EH;
VAR
prng : XkissArState;
i, u : INTEGER;
BEGIN
u := 0;
XkissArInit(prng, 12345678, 3, 2);
FOR i := 1 TO 1000000 DO
u := XkissArNext(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(XkissArNext(prng), 5);
Out.Ln()
END;
RETURN u = uref
END XkissArTest;
BEGIN
IF XkissArTest() THEN
Out.String("Passed")
ELSE
Out.String("Failed")
END
END xkiss.