summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2024-03-20 03:38:00 -0300
committerEuAndreh <eu@euandre.org>2024-03-20 03:38:05 -0300
commit4ce404bc32e46b7cdcb834f0077cda2219988e44 (patch)
treeb86a2735e20e876c08718986f8d32a514df4a502
parenttests/js/hero.mjs: Fix function ordering (diff)
downloadpapod-4ce404bc32e46b7cdcb834f0077cda2219988e44.tar.gz
papod-4ce404bc32e46b7cdcb834f0077cda2219988e44.tar.xz
tests/rand.mjs: Add MersenneTwister random number generator
The `tests/rand.c` is also added: a simplified adaptation of the original algorithm implementation in C. A 10k numbers test case shows that the JavaScript version behaves the same that the C one does.
-rw-r--r--.gitignore2
-rw-r--r--Makefile14
-rw-r--r--deps.mk1
-rw-r--r--tests/js/rand.mjs96
-rw-r--r--tests/rand.c83
-rw-r--r--tests/rand.mjs55
6 files changed, 249 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 7b4cefe..2c28a19 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
/doc/*.[0-9]
/doc/*.3js
/tests/hero-mkfifo-0.pipe
+/tests/*.bin
+/tests/bigger-rand-output.txt
diff --git a/Makefile b/Makefile
index 1870773..6ea0735 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ DESTDIR =
.SUFFIXES:
-.SUFFIXES: .in
+.SUFFIXES: .in .c .bin
.in:
sed \
@@ -34,6 +34,9 @@ DESTDIR =
< $< > $@
if [ -x $< ]; then chmod +x $@; fi
+.c.bin:
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
+
all:
@@ -53,6 +56,8 @@ installable = \
derived-assets = \
$(manpages) \
+ tests/rand.bin \
+ tests/bigger-rand-output.txt \
side-assets = \
tests/hero-*.pipe \
@@ -68,8 +73,13 @@ side-assets = \
## and installation.
all: $(derived-assets)
+tests/bigger-rand-output.txt: tests/rand.bin
+ printf '[\n\t%s\n]\n' \
+ "`./$? | tr '\n' ',' | sed -e 's|,$$||' -e 's|,|,\n\t|g'`" > $@
+
-$(manpages): Makefile deps.mk
+tests/rand.bin $(manpages): Makefile deps.mk
+tests/js/rand.mjs-check: tests/bigger-rand-output.txt
diff --git a/deps.mk b/deps.mk
index 320dc3d..ae0edc6 100644
--- a/deps.mk
+++ b/deps.mk
@@ -15,6 +15,7 @@ tests.mjs = \
tests/js/escape.mjs \
tests/js/hero.mjs \
tests/js/ircd.mjs \
+ tests/js/rand.mjs \
tests/js/utils.mjs \
tests/js/web.mjs \
diff --git a/tests/js/rand.mjs b/tests/js/rand.mjs
new file mode 100644
index 0000000..4044bb8
--- /dev/null
+++ b/tests/js/rand.mjs
@@ -0,0 +1,96 @@
+import assert from "node:assert/strict";
+import fs from "node:fs";
+
+import * as runner from "../runner.mjs";
+import {
+ makeRandom,
+} from "../rand.mjs";
+
+
+const test_makeRandom = async t => {
+ t.start("makeRandom()");
+
+ await t.test("known expected values", () => {
+ const expected1 = [
+ 545331265, 2211535594, 4152021490, 3857419313,
+ 1118735928, 3031474347, 3853601519, 3345048107,
+ 1618127707, 4001288224, 1444061399, 2700534436,
+ 1938647176, 1459718602, 3608868106, 926825740,
+ 528719691, 508226068, 2332279787, 357437743,
+ 1602075314, 1655472598, 1924131686, 4125580919,
+ 555943458, 4047836046, 3693150918, 1515015978,
+ 3523541186, 753964207, 1512058436, 682070622,
+ 983063469, 4097791860, 3336260823, 603291380,
+ 2554576084, 139062484, 590788013, 3608810491,
+ 3663176645, 3481732081, 1011496919, 2935401636,
+ 628041163, 3997974947, 2533467101, 2287863463,
+ 2465361808, 1196937660, 263152482, 618228754,
+ 2535860367, 3089904367, 1053769440, 1270818139,
+ 1462199892, 49766906, 4229377745, 445624458,
+ 3949395950, 4102223196, 162228180, 352248782,
+ 3700326028, 965464548, 3236553557, 1342363444,
+ 1740229486, 4006226087, 1475432391, 2100043423,
+ 734083679, 2197742340, 1695047538, 2684537025,
+ 2755935210, 2185177924, 1179365521, 682202996,
+ 1985796754, 1203188028, 3742512741, 2573038834,
+ 1722845493, 971634808, 2622456659, 1542773708,
+ 506664990, 516191900, 3015858858, 2439287065,
+ 1778261054, 3352336947, 1470361474, 2832338531,
+ 2559479753, 2841821596, 858410480, 1311022275,
+ ];
+
+ const expected2 = [
+ 1867215825, 1512725508, 59490082, 898255083,
+ 2128587452, 3375572255, 3011978101, 664390052,
+ 712189293, 1309145867, 1574443536, 3005563625,
+ 1937221174, 2592810353, 1221596501, 3864084723,
+ 2447880554, 1373397507, 4101388729, 1434258649,
+ 2876658371, 694177935, 1850641240, 2934786942,
+ 3613830458, 3660625740, 1450431957, 978896710,
+ 108365537, 1669305275, 1505684879, 1989942961,
+ 4089952722, 2832268551, 27863256, 3866494241,
+ 3916427650, 3309597508, 24597008, 3442418170,
+ 1617059167, 175885832, 854293503, 3965431971,
+ 3276364445, 4079612430, 1622146979, 1665096344,
+ 2283667308, 2042586700, 2997013224, 1214521941,
+ 860865914, 3204144669, 3352312876, 407025370,
+ 1854088521, 1518454983, 2467488963, 3014922727,
+ 667505194, 1382726996, 3519130642, 3473985175,
+ 387425140, 826920070, 3222196824, 3272392876,
+ 2814202151, 1958017767, 2343175108, 513394477,
+ 983853656, 3389045986, 177790781, 1853562919,
+ 1417029053, 115479138, 3505632337, 339954849,
+ 2552460743, 1260703764, 1719642924, 3129628830,
+ 1828716278, 3537151540, 4169628597, 444526909,
+ 4191927207, 3891278677, 1954375449, 3973495864,
+ 2231816005, 4062939046, 2084239497, 3470238230,
+ 1145760705, 2114090486, 4245867725, 1687967890,
+ ];
+
+ const expected3 = JSON.parse(
+ fs.readFileSync("tests/bigger-rand-output.txt"),
+ );
+
+ const given1 = Array.from(
+ new Array(expected1.length),
+ makeRandom(123456),
+ );
+ const given2 = Array.from(
+ new Array(expected2.length),
+ makeRandom(123457),
+ );
+ const given3 = Array.from(
+ new Array(expected3.length),
+ makeRandom(2222),
+ );
+
+ assert.deepEqual(given1, expected1);
+ assert.deepEqual(given2, expected2);
+ assert.deepEqual(given3, expected3);
+ });
+};
+
+
+await runner.runTests([
+ test_makeRandom,
+]);
diff --git a/tests/rand.c b/tests/rand.c
new file mode 100644
index 0000000..925d1ba
--- /dev/null
+++ b/tests/rand.c
@@ -0,0 +1,83 @@
+// Taken from
+// http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/MT2002/CODES/mt19937ar.c
+
+#define _XOPEN_SOURCE 700
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+
+#define N 624U
+static const uint16_t M = 397;
+static const uint32_t MATRIX_A = 0x9908b0dfUL;
+static const uint32_t UPPER_MASK = 0x80000000UL;
+static const uint32_t LOWER_MASK = 0x7fffffffUL;
+
+static uint32_t mt[N];
+static uint16_t mti;
+static bool initialized = false;
+
+static void
+init(uint32_t s) {
+ initialized = true;
+ mt[0] = s & 0xffffffffUL;
+ for (mti = 1; mti < N; mti++) {
+ mt[mti] = (1812433253 * (mt[mti - 1] ^ (mt[mti - 1] >> 30))) + mti;
+ }
+}
+
+/// Generates a random number on the [ 0, 0xffffffff ]-interval.
+static uint32_t
+generate(void) {
+ assert(initialized == true);
+ static uint32_t mag01[2] = { 0, MATRIX_A };
+
+ if (mti >= N) {
+ uint16_t kk;
+
+ for (kk = 0; kk < N - M; kk++) {
+ const uint32_t y0 =
+ (mt[kk] & UPPER_MASK) |
+ (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + M] ^ (y0 >> 1) ^ mag01[y0 & 1U];
+ }
+
+ for (; kk < N - 1; kk++) {
+ const uint32_t y1 =
+ (mt[kk] & UPPER_MASK) |
+ (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + (M - N)] ^ (y1 >> 1) ^ mag01[y1 & 1U];
+ }
+
+ const uint32_t y2 =
+ (mt[N - 1] & UPPER_MASK) |
+ (mt[0] & LOWER_MASK);
+ mt[N - 1] = mt[M - 1] ^ (y2 >> 1) ^ mag01[y2 & 1U];
+ mti = 0;
+ }
+
+ uint32_t y = mt[mti++];
+
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+
+ return y;
+}
+
+
+int
+main(void) {
+ init(2222);
+
+ for (uint16_t i = 0; i < 10000; i++) {
+ assert(
+ printf("%" PRIu32 "\n", generate()) > 0
+ );
+ }
+
+ return 0;
+}
diff --git a/tests/rand.mjs b/tests/rand.mjs
new file mode 100644
index 0000000..ba4e3b1
--- /dev/null
+++ b/tests/rand.mjs
@@ -0,0 +1,55 @@
+const N = 624;
+const M = 397;
+const MATRIX_A = 0x9908b0df;
+const UPPER_MASK = 0x80000000;
+const LOWER_MASK = 0x7fffffff;
+const mag01 = [ 0x0, MATRIX_A ];
+const INIT_MUL = 1812433253;
+
+/// The given function generates random numbers on the [ 0, 0xffffffff ]-interval.
+export const makeRandom = (seed = (new Date()).getTime()) => {
+ const mt = new Array(N);
+ let mti = null;
+
+ mt[0] = seed >>> 0;
+ for (mti = 1; mti < N; mti++) {
+ const s0 = mt[mti - 1] ^ (mt[mti - 1] >>> 30);
+ mt[mti] =
+ (((((s0 & 0xffff0000) >>> 16) * INIT_MUL) << 16) +
+ (( s0 & 0x0000ffff) * INIT_MUL) +
+ mti) >>> 0;
+ }
+
+ return () => {
+ if (mti >= N) {
+ let kk = null;
+
+ for (kk = 0; kk < N - M; kk++) {
+ const y0 =
+ (mt[kk] & UPPER_MASK) |
+ (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + M] ^ (y0 >>> 1) ^ mag01[y0 & 0x1];
+ }
+
+ for (; kk < N - 1; kk++) {
+ const y1 =
+ (mt[kk] & UPPER_MASK) |
+ (mt[kk + 1] & LOWER_MASK);
+ mt[kk] = mt[kk + (M - N)] ^ (y1 >>> 1) ^ mag01[y1 & 0x1];
+ }
+
+ const y2 =
+ (mt[N - 1] & UPPER_MASK) |
+ (mt[0] & LOWER_MASK);
+ mt[N - 1] = mt[M - 1] ^ (y2 >>> 1) ^ mag01[y2 & 0x1];
+ mti = 0;
+ }
+
+ let y = mt[mti++];
+ y ^= (y >>> 11);
+ y ^= (y << 7) & 0x9d2c5680;
+ y ^= (y << 15) & 0xefc60000;
+ y ^= (y >>> 18);
+ return y >>> 0;
+ };
+};