79 lines
2.5 KiB
Text
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
|