编辑:我的主要问题是我想在我的计算机上复制 TI-84 plus RNG 算法,所以我可以用 Javascript 或 Lua 等语言编写它,以更快地测试它。
我尝试使用模拟器,但结果比计算器慢。
仅针对有关人员:还有另一个类似的问题,但对该问题的回答只是说如何将已经生成的数字传输到计算机上。我不想要这个。我已经尝试过类似的方法,但我不得不让计算器运行整个周末,但仍然没有完成。
编辑:我的主要问题是我想在我的计算机上复制 TI-84 plus RNG 算法,所以我可以用 Javascript 或 Lua 等语言编写它,以更快地测试它。
我尝试使用模拟器,但结果比计算器慢。
仅针对有关人员:还有另一个类似的问题,但对该问题的回答只是说如何将已经生成的数字传输到计算机上。我不想要这个。我已经尝试过类似的方法,但我不得不让计算器运行整个周末,但仍然没有完成。
使用的算法来自P. L'Ecuyer的论文Efficient and便携式组合随机数生成器。
Ti 计算器使用的算法位于 p 的 RHS 一侧。747. 我附上了一张图片。
我已经把它翻译成一个 C++ 程序
#include <iostream>
#include <iomanip>
using namespace std;
long s1,s2;
double Uniform(){
long Z,k;
k = s1 / 53668;
s1 = 40014*(s1-k*53668)-k*12211;
if(s1<0)
s1 = s1+2147483563;
k = s2/52774;
s2 = 40692*(s2-k*52774)-k*3791;
if(s2<0)
s2 = s2+2147483399;
Z=s1-s2;
if(Z<1)
Z = Z+2147483562;
return Z*(4.656613e-10);
}
int main(){
s1 = 12345; //Gotta love these seed values!
s2 = 67890;
for(int i=0;i<10;i++)
cout<<std::setprecision(10)<<Uniform()<<endl;
}
请注意,初始种子是s1 = 12345
和s2 = 67890
。
并从 Ti-83(对不起,我找不到 Ti-84 ROM)仿真器得到输出:
这符合我的实现产生的
我刚刚提高了实现的输出精度并得到了以下结果:
0.9435973904
0.9083188494
0.1466878273
0.5147019439
0.4058096366
0.7338123019
0.04399198693
0.3393625207
请注意,它们与 Ti 的结果在不太重要的数字上有所不同。这可能是两个处理器(Ti 的 Z80 与我的 X86)执行浮点计算的方式不同。如果是这样,就很难克服这个问题。尽管如此,随机数仍然会以相同的序列生成(下面有警告),因为该序列仅依赖于整数数学,这是精确的。
我还使用该long
类型来存储中间值。Ti 实现依赖于整数溢出存在一些风险(我没有仔细阅读 L'Ecuyer 的论文),在这种情况下,您必须调整到int32_t
或类似的类型来模拟这种行为。再次假设处理器执行类似。
编辑
该站点提供了代码的 Ti-Basic 实现,如下所示:
:2147483563→mod1
:2147483399→mod2
:40014→mult1
:40692→mult2
#The RandSeed Algorithm
:abs(int(n))→n
:If n=0 Then
: 12345→seed1
: 67890→seed2
:Else
: mod(mult1*n,mod1)→seed1
: mod(n,mod2)→seed2
:EndIf
#The rand() Algorithm
:Local result
:mod(seed1*mult1,mod1)→seed1
:mod(seed2*mult2,mod2)→seed2
:(seed1-seed2)/mod1→result
:If result<0
: result+1→result
:Return result
我将其翻译成 C++ 进行测试:
#include <iostream>
#include <iomanip>
using namespace std;
long mod1 = 2147483563;
long mod2 = 2147483399;
long mult1 = 40014;
long mult2 = 40692;
long seed1,seed2;
void Seed(int n){
if(n<0) //Perform an abs
n = -n;
if(n==0){
seed1 = 12345; //Gotta love these seed values!
seed2 = 67890;
} else {
seed1 = (mult1*n)%mod1;
seed2 = n%mod2;
}
}
double Generate(){
double result;
seed1 = (seed1*mult1)%mod1;
seed2 = (seed2*mult2)%mod2;
result = (double)(seed1-seed2)/(double)mod1;
if(result<0)
result = result+1;
return result;
}
int main(){
Seed(0);
for(int i=0;i<10;i++)
cout<<setprecision(10)<<Generate()<<endl;
}
这给出了以下结果:
0.9435974025
0.908318861
0.1466878292
0.5147019502
0.405809642
0.7338123114
0.04399198747
0.3393625248
0.9954663411
0.2003402617
这与基于原始论文的实现相匹配。
我在 Python 中实现了 rand、randInt、randM 和 randBin。感谢 Richard 提供的 C 代码。所有实现的命令都按预期工作。您也可以在此 Gist中找到它。
import math
class TIprng(object):
def __init__(self):
self.mod1 = 2147483563
self.mod2 = 2147483399
self.mult1 = 40014
self.mult2 = 40692
self.seed1 = 12345
self.seed2 = 67890
def seed(self, n):
n = math.fabs(math.floor(n))
if (n == 0):
self.seed1 = 12345
self.seed2 = 67890
else:
self.seed1 = (self.mult1 * n) % self.mod1
self.seed2 = (n)% self.mod2
def rand(self, times = 0):
# like TI, this will return a list (array in python) if times == 1,
# or an integer if times isn't specified
if not(times):
self.seed1 = (self.seed1 * self.mult1) % self.mod1
self.seed2 = (self.seed2 * self.mult2)% self.mod2
result = (self.seed1 - self.seed2)/self.mod1
if(result<0):
result = result+1
return result
else:
return [self.rand() for _ in range(times)]
def randInt(self, minimum, maximum, times = 0):
# like TI, this will return a list (array in python) if times == 1,
# or an integer if times isn't specified
if not(times):
if (minimum < maximum):
return (minimum + math.floor((maximum- minimum + 1) * self.rand()))
else:
return (maximum + math.floor((minimum - maximum + 1) * self.rand()))
else:
return [self.randInt(minimum, maximum) for _ in range(times)]
def randBin(self, numtrials, prob, times = 0):
if not(times):
return sum([(self.rand() < prob) for _ in range(numtrials)])
else:
return [self.randBin(numtrials, prob) for _ in range(times)]
def randM(self, rows, columns):
# this will return an array of arrays
matrixArr = [[0 for x in range(columns)] for x in range(rows)]
# we go from bottom to top, from right to left
for row in reversed(range(rows)):
for column in reversed(range(columns)):
matrixArr[row][column] = self.randInt(-9, 9)
return matrixArr
testPRNG = TIprng()
testPRNG.seed(0)
print(testPRNG.randInt(0,100))
testPRNG.seed(0)
print(testPRNG.randM(3,4))
TI-Basicrand
命令使用的算法是根据TIBasicDev的 L'Ecuyer 算法。
rand 生成一个介于 0 和 1 之间的均匀分布的伪随机数(为了简单起见,本页和其他页面有时会去掉伪前缀)。 rand(n) 生成一个介于 0 和 1 之间的 n 个均匀分布的伪随机数的列表。种子→rand种子(初始化)内置的伪随机数生成器。出厂默认种子为 0。
TI 计算器使用 L'Ecuyer 算法生成伪随机数。
不幸的是,我无法找到德州仪器 (TI) 发布的任何支持此声明的来源,因此我无法确定这是使用的算法。我也不确定 L'Ecuyer 算法到底指的是什么。