RosettaCodeData/Task/Linear-congruential-generator/ALGOL-68/linear-congruential-generator.alg
2023-07-01 13:44:08 -04:00

79 lines
2.5 KiB
Text

BEGIN
COMMENT
Algol 68 Genie checks for integer overflow whereas the reference
language leaves the result undefined so for portability we need to
see how wide a variable must be to hold the maximum possible value
before range reduction. This occurs in the BSD RNG when
rseed=2147483647 and is therefore 2147483647 * 1103515245 + 12345 =
2369780942852710860, which itself is 19 decimal digits. Use
evironmental queries to determine the width needed.
COMMENT
MODE RANDINT = UNION (INT, LONG INT, LONG LONG INT);
RANDINT rseed := (int width > 18 | 0 |:
long int width > 18 |
LONG 0 | LONG LONG 0);
PROC srand = (INT x) VOID :
(rseed | (INT): rseed := x,
(LONG INT): rseed := LENG x | rseed := LENG LENG x);
PROC bsd rand = INT :
BEGIN
CASE rseed IN
(INT ri):
BEGIN
INT a = 1103515245, c = 12345, m1 = 2^16, m2 = 2^15;
COMMENT
That curious declaration is because 2^31 might overflow during
compilation but the MODE declaration for RANDINT guarantees that it
will not overflow at run-time. We assume that an INT is at least
32 bits wide, otherwise a similar workaround would be needed for
the declaration of a.
COMMENT
INT result = (ri * a + c) MOD (m1 * m2); rseed := result;
result
END,
(LONG INT rli):
BEGIN
LONG INT a = LONG 1103515245, c = LONG 12345, m = LONG 2^31;
LONG INT result = (rli * a + c) MOD m; rseed := result;
SHORTEN result
END,
(LONG LONG INT rlli) :
BEGIN
LONG LONG INT a = LONG LONG 1103515245,
c = LONG LONG 12345, m = LONG LONG 2^31;
LONG LONG INT result = (rlli * a + c) MOD m; rseed := result;
SHORTEN SHORTEN result
END
ESAC
END;
PROC ms rand = INT :
BEGIN
CASE rseed IN
(INT ri):
BEGIN
INT a = 214013, c = 2531011, m1 = 2^15, m2 = 2^16;
INT result = (ri * a + c) MOD (m1 * m2); rseed := result;
result % m2
END,
(LONG INT rli):
BEGIN
LONG INT a = LONG 214013, c = LONG 2531011, m = LONG 2^31, m2 = LONG 2^16;
LONG INT result = (rli * a + c) MOD m; rseed := result;
SHORTEN (result % m2)
END,
(LONG LONG INT rlli) :
BEGIN
LONG LONG INT a = LONG LONG 214013,
c = LONG LONG 2531011, m = LONG LONG 2^31, m2 = LONG LONG 2^16;
LONG LONG INT result = (rlli * a + c) MOD m; rseed := result;
SHORTEN SHORTEN (result % m2)
END
ESAC
END;
srand (0);
TO 10 DO printf (($g(0)l$, bsd rand)) OD;
print (newline);
srand (0);
TO 10 DO printf (($g(0)l$, ms rand)) OD;
srand (0)
END