Finding the Seed of the rand() Function TI-84 Programming
我已经对该TI-84 rand()函数进行了大量研究。 它使用L'Ecuyer算法生成伪随机数。 我有一个有趣的案例。
如果给rand()函数适当的种子,它将始终生成相同的数字。 那么,给定rand()函数生成的第一个随机数,是否有可能找到该函数的种子?
令变量X代表未知种子。
1 2 3 | X->rand rand->D Disp D |
输出:
1 | 0.114820491 |
根据此信息,是否可以计算rand()函数的种子? 您能以某种方式从TI-84的rand()算法倒退吗?
不,根据经验,不可能仅基于第一个生成的随机数来计算种子,因为它不是唯一的。下面的代码将在给定第一个随机数的情况下用蛮力搜索种子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #include <stdio.h> #include <stdint.h> #include <math.h> #include <stdlib.h> int64_t mod1 = 2147483563; int64_t mod2 = 2147483399; int64_t mult1 = 40014; int64_t mult2 = 40692; int64_t seed1,seed2; void Seed(int64_t 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(int argc, char **argv){ double x = 0.114820491; // Mattkx4's value double r; int64_t n; int i; if (argc > 2) { printf("USAGE: %s <1st generated random number> ", argv[0]); return 1; } else if (argc == 2) { x = atof(argv[1]); printf("[Looking for seed generating %.10f] ", x); } else { printf("[Looking for seed generating default value of %.10f] ", x); } for (n=0; n<= 2147483647; n++) { Seed(n); r = Generate(); if (fabs(r-x) < 10e-10) { printf("HIT: seed is %ld; G()=%.10f, G()-x=%.12f ", (long) n, r, r-x); for (i=0; i<5; i++) { printf(" G() = %.10f ", Generate()); } } } return 0; } |
对于OP的第一个随机数,它将给出以下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | $ time ./a.out [Looking for seed generating default value of 0.1148204910] HIT: seed is 41817; G()=0.1148204909, G()-x=-0.000000000055 G() = 0.1928098124 G() = 0.8785866698 G() = 0.7541802051 G() = 0.3236799652 G() = 0.2698472063 HIT: seed is 196206349; G()=0.1148204909, G()-x=-0.000000000055 G() = 0.7255189385 G() = 0.3079613984 G() = 0.8041985209 G() = 0.0959226401 G() = 0.7729820570 HIT: seed is 392370881; G()=0.1148204909, G()-x=-0.000000000055 G() = 0.2582281409 G() = 0.7373361269 G() = 0.8542168367 G() = 0.8681653150 G() = 0.2761169842 HIT: seed is 588535413; G()=0.1148204909, G()-x=-0.000000000055 G() = 0.7909372669 G() = 0.1667108555 G() = 0.9042350761 G() = 0.6404079899 G() = 0.7792519113 HIT: seed is 1869313916; G()=0.1148204919, G()-x=0.000000000876 G() = 0.9421831845 G() = 0.2660259263 G() = 0.9001868100 G() = 0.3563914254 G() = 0.3884731955 HIT: seed is 2065478448; G()=0.1148204919, G()-x=0.000000000876 G() = 0.4748923105 G() = 0.6954006549 G() = 0.9502050494 G() = 0.1286341003 G() = 0.8916080463 real 1m24.132s user 1m24.179s sys 0m0.000s |
在回答这个问题时,我使用@richard提供的代码在这个stackoverflow问题的答案中站在巨人的肩膀上。如果有更好的方式来提供归因,请告诉我或直接编辑此答案。
我找到了一个解决方案,但我认为它不是最有效的系统。以下是我用来穷举搜索与rand数字匹配的程序。
1 2 3 4 5 6 7 8 9 10 | 0→C Repeat X=0.114820491 Disp C C→rand rand→X C+1→C End Disp"Done!" |
该程序测试每个种子的rand函数,直到最终找到产生所需随机数的种子。
该系统的问题在于存在大量的可能性。在这种情况下,该程序仅需运行40,000次以上,但是在某些情况下,该程序在找到匹配的种子之前将运行数百万次。但是,如果种子相对较小,则此方法有效。
这不是最好的解决方案,但它是一个解决方案。
有关更精确的方法,请参见@JimD。的答案。