2015-09-25 55 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))