2015-09-25 299 views
14

编辑:我的主要问题是,我想复制我的计算机上的TI-84加RNG算法,这样我就可以像Javascript或Lua的语言写,以测试它更快。TI-84 +随机数生成算法

我试过使用模拟器,但事实证明它比计算器慢。

只针对有关人员:还有另一个question这样,但回答这个问题只是说如何将已经生成的数字转移到计算机。我不想要这个。我已经尝试过类似的东西,但是我不得不让计算器整个周末都运行,但仍然没有完成。

+0

你能说清楚你的意思是“有人知道TI-84 plus计算器上的RNG是如何工作的吗?”我不明白你想要做什么。你想知道它是如何播种的吗?你想知道分配是多么随机的吗?你提到你跑了一个很长的测试,但没有明确的问题。 – Dan

+0

我编辑了这个问题。 – tupperkion

+0

所以你试图'测试'?目前还没有100%清楚你在这里做什么。你*不*只是想要很多像其他问题一样的随机样本? – Dan

回答

17

正在使用的算法来自纸张P.L'Ecuyer的高效便携式组合随机数发生器。您可以找到here的文件,并从here免费下载。

Ti计算器使用的算法位于p的RHS端。我已经收录了一张照片。

L'Ecuyer's Algorithm

我已经翻译成一个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 = 12345s2 = 67890这一点。

,并得到从TI-83的输出(对不起,我找不到一个TI-84 ROM)模拟器:

Ti-83 Screenshot

这符合什么我实现生产

My computer

我刚刚开始执行我的输出精度,并得到以下结果:

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或类似的类型来模拟此行为。再次假设处理器的表现类似。

编辑

This site提供的Ti-基本执行的代码如下:

: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 

它们与基于原始文件的实现相匹配。

+0

如果您拥有TI-84 + SE,则可以合法使用TI-84 + SE ROM,例如http://tibasic.com/rom/TI84PlusSE.rom – Timtech

+0

上的ROM。您可以从中获得2.55 OS TI网站,但2.43不再可用。如果你想下载,告诉我。我从TI的支持中获得了它,但仅仅是因为有人仍然把它放在PC上。 – Fabian

3

TI-Basic rand命令使用的算法是根据TIBasicDev的L'Ecuyer算法。

兰特生成均匀分布的伪随机数( 此主页等有时会下降为简单起见伪前缀) 0和1之间兰特(n)的生成n的列表均匀分布的伪随机 数字在0和1之间。种子→兰德种子(初始化) 内置伪随机数生成器。出厂默认种子 为0.

TI计算器使用L'Ecuyer算法生成 伪随机数。

不幸的是,我一直没有能够找到德州仪器公布的备份此声明的任何源代码,所以我不能肯定这是使用的algorthm。我也不确定L'Ecuyer算法提到的究竟是什么。

+0

'P. L'Ecuyer,“Combined Multiple Recursive Random Number Generators”,Operations Research,44,5(1996),816-822. –

+2

该链接详细描述了该算法:http://tibasicdev.wikidot.com/68k:randseed –

3

我在Python中实现了rand,randInt,randM和randBin。感谢理查德的C代码。所有实施的命令按预期工作。你也可以在this 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))