Java的Random函数接受一个种子,并产生一个“psuedo-random”数字序列。(它是基于Donald Knuth,The Art of Computer Programming,第3卷,第3.2.1节中讨论的一些算法实现的。)
,但文章太技术性了,我看不懂)
它有反函数吗?也就是说,给定一个数列,有可能从数学上确定种子是什么吗?(意思是,暴力强制不是一种有效的方法)
例如,函数y=f(x)=3x
有一个反函数,即y=g(x)=x/3
。
但是函数z=f(x,y)=x*y
没有反函数,因为(我可以在这里给出充分的数学证明,但我不想绕开我的主要问题),直观地说,有不止一对(x,y)
这样的(x*y)==z
。
现在回到我的问题,如果你说函数不可逆,请解释为什么。
(我希望从那些真正读过这篇文章并理解它的人那里得到答案。像“这是不可能的”这样的答案并没有真正的帮助。)
如果我们讨论的是java.util.random
的Oracle(Née Sun)实现,那么是的,只要您知道足够多的位,这是可能的。
random
使用48位种子和线性同余生成器。这些不是密码安全的发电机,因为州的规模很小(残酷的力量!)而且输出并不是随机的(许多发生器在某些位上会显示小的周期长度,这意味着即使其他位看起来是随机的,这些位也可以很容易地预测出来)。
random
的种子更新如下:
nextseed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
这是一个非常简单的函数,如果你通过计算知道种子的所有比特,它就可以反演
seed = ((nextseed - 0xBL) * 0xdfe05bcb1365L) & ((1L << 48) - 1)
因为0x5DEECE66DL*0xDFE05BCB1365L=1
mod 248。这样,任何时间点的单个种子值就足以恢复所有过去和将来的种子。
但是random
没有显示整个种子的函数,所以我们必须稍微聪明一点。
让我们具体看看nextlong
。它返回一个数字(a<<32)+B
,其中a
和B
都是32位的量。在调用NextLong
之前,让s
作为种子。然后,设t=s*0x5DEECE66DL+0xBL
,使A
为t
的高32位,设U=t*0x5DEECE66DL+0xBL
,使B
为U
的高32位。设C
和D
分别为T
和U
的低16位。
注意,由于c
和d
是16位的量,我们可以硬性地强制它们(因为我们只需要一个)并完成它。这是相当便宜的,因为216只有65536--对于一台电脑来说很小。但让我们聪明一点看看有没有更快的方法。
我们有(b<<16)+d=((a<<16)+c)*0x5DEECE66DL+11
。因此,通过代数运算,我们得到了(b<<16)-11-(a<<16)*0x5deece66dl=C*0x5deece66dl-d
,mod248。由于C
和D
都是16位量,C*0x5DEECE66DL
最多有51位。这很有意义地意味着
(b << 16) - 11 - (a << 16)*0x5DEECE66DL + (k<<48)
对于某些k
,最多等于C*0x5DEECE66dl-d
。(计算C
和D
有更复杂的方法,但因为K
的界限很小,所以更容易使用暴力)。
我们只需测试K
的所有可能值,直到我们得到一个值,该值被否定的余数mod0x5deece66dl
是16位(又是mod248),这样我们就可以恢复T
和U
的低16位。在这一点上,我们有一个完整的种子,所以我们可以使用第一个方程找到未来的种子,或者使用第二个方程找到过去的种子。
演示该方法的代码:
import java.util.Random;
public class randhack {
public static long calcSeed(long nextLong) {
final long x = 0x5DEECE66DL;
final long xinv = 0xdfe05bcb1365L;
final long y = 0xBL;
final long mask = ((1L << 48)-1);
long a = nextLong >>> 32;
long b = nextLong & ((1L<<32)-1);
if((b & 0x80000000) != 0)
a++; // b had a sign bit, so we need to restore a
long q = ((b << 16) - y - (a << 16)*x) & mask;
for(long k=0; k<=5; k++) {
long rem = (x - (q + (k<<48))) % x;
long d = (rem + x)%x; // force positive
if(d < 65536) {
long c = ((q + d) * xinv) & mask;
if(c < 65536) {
return ((((a << 16) + c) - y) * xinv) & mask;
}
}
}
throw new RuntimeException("Failed!!");
}
public static void main(String[] args) {
Random r = new Random();
long next = r.nextLong();
System.out.println("Next long value: " + next);
long seed = calcSeed(next);
System.out.println("Seed " + seed);
// setSeed mangles the input, so demangle it here to get the right output
Random r2 = new Random((seed ^ 0x5DEECE66DL) & ((1L << 48)-1));
System.out.println("Next long value from seed: " + r2.nextLong());
}
}
问题 你想要获得两个整数(包含在内)之间的一个随机整数。 解决方案 使用以下的函数。 randomInt = (lower, upper) -> [lower, upper] = [0, lower] unless upper? # 用一个参数调用 [lower, upper] = [upper, lower] if lower > upper #
函数名称:获取随机数 函数功能:获取真随机数,随机数值 函数方法 num = getRndNum(min,max); 参数 类型 必填 说明 min number 是 随机范围的整数最小值 max number 是 随机范围的整数最大值 参数 类型 说明 num number 获取到的随机数 函数用例 num = getRndNum(1,100) -- 随机获取一个 1 - 100 之间的数字 d
本文向大家介绍python中的随机函数小结,包括了python中的随机函数小结的使用技巧和注意事项,需要的朋友参考一下 本系列不会对python语法,理论作详细说明;所以不是一个学习教材;而这里只是我一个学习python的某些专题的总结。 1. random()函数 描述:random() 方法返回随机生成的一个实数,它在[0,1)范围内。 语法: 注意:random()是不能直接访问的
本文向大家介绍PHP随机字符串函数,包括了PHP随机字符串函数的使用技巧和注意事项,需要的朋友参考一下 我今天正在测试一个字符串操作函数(我将在其他时间发布),我想创建一个可以输入的随机字符串,因此我想出了下面的函数。我以为这是PHPrand()和chr()PHP函数的巧妙用法,所以就在这里。 它通过选择要使用的字符类型(例如大写字母,数字等),然后使用该chr()函数随机选择一个字符来工作。该c
随机变量的函数 在前面的文章中,我先将概率值分配给各个事件,得到事件的概率分布。 通过事件与随机变量的映射,让事件“数值化”,事件的概率值转移到随机变量上,获得随机变量的概率分布。 我们使用随机变量的函数,来定制新的随机变量。随机变量的函数是从旧有的随机变量到一个新随机变量的映射。通过函数的映射功能,原有随机变量对应新的随机变量。通过原有随机变量的概率分布,我们可以获知新随机变量的概率分布。事件,
本文向大家介绍PHP也能干大事 随机函数,包括了PHP也能干大事 随机函数的使用技巧和注意事项,需要的朋友参考一下 写在前面 PHP也能干大事是我总结的PHP语法特性及相关函数类库的经典用法,并不一定是真正能实现四两拨千斤的功效,但是掌握这些方法,可以在你的工作和学习上有一些帮助,希望大家能集思广益,将《PHP也能干大事》丰富得更精彩!转载请注明出处(3mc2.com) 二、前言 PHP是常见的脚