On emulating the Texas Instruments random number generator

I recently needed to emulate the random number generator internally used by Texas Instruments calculators in Mathematica. Thanks to this United-TI forum post, I found that the algorithm being used is a combined multiplicative linear congruential generator due to Pierre L’Ecuyer. The particular generator used is listed on page 747 of the article; as noted there, the combined MLCG has a period of 2305842648436451838\approx 2.30584\times10^{18}.

I figured this might be useful to other people, so I’m posting the routines needed to get RandomReal[] and related functions to emulate the rand() function (and ilk) on TI calculators:

TexasInstruments /: Random`InitializeGenerator[TexasInstruments, ___] := TexasInstruments[12345, 67890]

TexasInstruments[___]["GeneratesRealsQ"] := True;
TexasInstruments[___]["GeneratesIntegersQ"] := True;

TexasInstruments[___]["SeedGenerator"[seed_]] := If[seed == 0, TexasInstruments[12345, 67890],
TexasInstruments[Mod[40014 seed, 2147483563],
Mod[seed, 2147483399]]];

TexasInstruments[s1_, s2_]["GenerateReals"[n_, {a_, b_}, prec_]] :=
Module[{p = s1, q = s2, temp},
{a + (b - a) Table[p = Mod[40014 p, 2147483563]; q = Mod[40692 q, 2147483399]; temp = (p - q)/2147483563; If[temp < 0, temp += 1]; temp, {n}], TexasInstruments[p, q]}
]

TexasInstruments[s1_, s2_]["GenerateIntegers"[n_, {a_, b_}]] :=
Module[{p = s1, q = s2, temp},
{a + Floor[(b - a + 1) Table[p = Mod[40014 p, 2147483563]; q = Mod[40692 q, 2147483399]; temp = (p - q)/2147483563; If[temp < 0, temp += 1]; temp, {n}]], TexasInstruments[p, q]}
]

This is based on the PRNG method plug-in framework in Mathematica that is described here. For instance, here is the Mathematica equivalent of executing 0→rand:rand(10) (for Zilog Z80 calculators like the TI-83 Plus) or RandSeed 0:rand() (for Motorola 68k calculators like the TI-89):

(* 0→rand:rand(10) *)
BlockRandom[SeedRandom[0, Method -> TexasInstruments];
RandomReal[{0, 1}, 10, WorkingPrecision -> 20]]

Here’s corresponding code for randInt() and randM() on the Z80 calculators:

(* 0->rand:randInt(1,10,10) *)
BlockRandom[SeedRandom[0, Method -> TexasInstruments];
RandomInteger[{1, 10}, 10]]

(* 0->rand:randM(3,3) *)
BlockRandom[SeedRandom[0, Method -> TexasInstruments];
Reverse[Reverse /@ RandomInteger[{-9, 9}, {3, 3}]]]

Due to differences in precision, there is bound to be some discrepancy in the least significant figures of the results from the calculators and the results from the Mathematica emulation; still, I believe that this is a serviceable fake.

2 thoughts on “On emulating the Texas Instruments random number generator

Leave a comment