JAVA语言随机数的产生及其应用

【摘要】
随机数在现代密码学领域有着极其广泛地应用。在密码学中,对一个序列的随机性是这样定义的:①看起来是随机的,即能通过我们所能找到的所有正确的随机性检验。②这个序列是不可预测的,也就是说,即使给出产生序列的算法或者硬件设计和以前产生序列的所有知识,也不可能通过计算来预测下一个比特是什么。③这个序列不能重复产生,即使在完全相同的操作条件下用完全相同的输入对序列发生器操作两次,也将得到两个完全不同的、毫不相关的位序列。
【全文】
        随机数在现代密码学领域有着极其广泛地应用。在密码学中,对一个序列的随机性是这样定义的:①看起来是随机的,即能通过我们所能找到的所有正确的随机性检验。②这个序列是不可预测的,也就是说,即使给出产生序列的算法或者硬件设计和以前产生序列的所有知识,也不可能通过计算来预测下一个比特是什么。③这个序列不能重复产生,即使在完全相同的操作条件下用完全相同的输入对序列发生器操作两次,也将得到两个完全不同的、毫不相关的位序列。
随机数产生方法一般有三种。方法1——手工法,如采用抽签、掷骰子、摇号或从搅乱的袋中取出带数字的球等方法,当今的福利彩票就采用该方法;方法2——物理方法,在计算机上安装一台物理随机数发生器,把具有随机性质的物理过程变换为随机数,如附加一个某种放射粒子的放射源,用计数器记录下某段时间内放射出的粒子数,得到真正的随机数;方法3——数学方法,高级编程语言一般用此法生成随机数。
在计算机上用数学方法产生某一分布的随机数,由于是依照某种算法产生的,就不可能是真正的随机数(即不满足定义条件③),因此常把数学方法产生的随机数称为伪随机数。只要伪随机数具有真正随机数的一些统计性质,就可以把伪随机数作为真正随机数来使用。
JAVA语言随机数产生原理
        JAVA语言是采用数学方法——线性同余法(Liner Congruence Generator,即LCG法)产生随机数的。有整数a,b,M;M 为模并M > 0,若b - a为M 的倍数。则有a,b 分别除以M后,所得余数相同。则称a 与b 关于模M 同余,记为:a≡b (modM)。
例如:11 ≡1 (mod10);1 ≡11 (mod10);12 ≡60 (mod16)
LCG方法的一般递推公式为:
Xn = (aXn - 1 + c) (modM)
Rn = Xn/ M
初值X0   (n = 1 ,2 , &S943;&S943;)
其中M为模数,a为乘子(乘数) ,c为增量(加数),且Xn ,M,a,c均为非负整数。
由上式得到的Xn (n = 1 ,2 , &S943;&S943;) 满足:0 ≤Xn < M,从而Rn ∈[0 ,1 ] 。
应用递推公式产生均匀分布随机数时,式中参数a,c,X0,M的选取十分重要。
例如,取M = 10,a = c = X0 = 7,得
{Xn} :6 ,9 ,0 ,7 ,6 ,9 ,0 ,7 &S943;&S943;周期为4。
例如,取M=16,a=5,c=3,X0=7,得
{Xn} :6 ,1 ,8 ,11 ,10 ,5 ,12 ,15 ,14 ,9 ,0 ,3 ,2 ,13 ,4 ,7 ,6 ,1 &S943;&S943;周期为16。
例如,取M = 8,a = 5,c = 1,X0 = 1,得
{Xn} :6 ,7 ,4 ,2 ,3 ,0 ,1 ,6 ,7 &S943;&S943;周期为8。
LCG方法产生的随机数在周期内不会重复。
线性同余法产生的伪随机数具有随机性好、周期长,易于计算机实现和速度快等特点而被广泛采用。但用线性同余法产生的随机数因受到数学规律的影响而具有周期性和相关性。
Java语言通过java.util.Random类产生一个随机数发生器。它有两种形式的构造函数,分别是Random()和Random(long seed)。随机数发生器即Random对象产生以后,可以通过对象调用不同的函数:nextInt()、nextLong()、nextFloat()、nextDouble()等来获得不同类型的随机数。
某范围内可重复和不可重复随机数的产生方法
        在实际随机产生及应用过程中,根据整数随机数范围性和是否可重复性,可分为某范围内可重复和某范围内不可重复。
(1)生成10个在区间[100,300]内可重复的随机数:
import java.util.*;
class RandomTest {
public static void main(String[] args) {
       int lowerbound = 100;
    int upperbound = 300;
    Random random1 = new Random();
    for (int i=1;i<=10;i++){
            int rndnumber = random1.nextInt(upperbound-lowerbound+1) + lowerbound;
            System.out.println("第"+i+"个随机数:"+rndnumber);
    }
}
}
(2)生成10个在区间[100,300]内不可重复的随机数:
import java.util.*;
class RandomTest {
     public static void main(String[] args) {
            int lowerbound = 100;
           int upperbound = 300;
           int lastindex=upperbound-lowerbound+1;
           int rndavailable[] = new int[lastindex];
           Random random1 = new Random();
           for (int i=lowerbound;i<=upperbound;i++)
                  rndavailable[i-lowerbound]=i;
           for (int i=1;i<=10;i++){
                  int rndindex=random1.nextInt(lastindex);
                 System.out.println("第"+i+"个随机数:"+rndavailable[rndindex]);
                 rndavailable[rndindex]=rndavailable[lastindex-1];
                 lastindex--;
           }
       }
}
产生一定范围内不可重复的随机数,不能按通常的思路:把曾经生成的随机数保存起来作为历史数据。产生一个新的随机数后在历史数据中搜索,若找到就重新产生一个新的再重复数据搜索;否则就认为已经找到了一个新的不同随机数。
        从数学的角度来说,概率上存在每次产生的随机数都相同的可能性,尽管这种可能性很小。换言之,按上述思路编制的程序在运行过程中可能会导致死循环!从算法的角度来讲,在理论上,程序失去了有穷性、有效性和确定性。
       正因为如此,上述程序代码把要产生的所有数放到一个数组rndavailable中,每次随机生成数组rndavailable的一个下标rndindex,然后取出它所对应的数据,将数组rndavailable的最后一个数放到下标rndindex的位置,同时将数组rndavailable的长度减1。这样每一次生成的随机数都不会一样,从而保证了算法的确定性、有效性和有穷性。
        JAVA随机数发生器产生的是伪随机数,是由随机种子根据一定的计算方法计算出来的数值。所以,只要计算方法一定,随机种子一定,那么产生的随机数就是固定的。Random()使用当前时间即System.currentTimeMillis()作为发生器的种子,由于每次调用时的时间不同,所以产生的随机数序列也不同。在产生某范围内不可重复的随机数应用中,要充分考虑算法确定性、有效性和有穷性。
        真正的随机数是不可能通过具体的算法生成的,只能来源于随机事件。如何利用计算机中的随机事件快捷产生真正的随机数一直是计算机研究人员探索的热点课题。
 
Java程序设计》课程实验指导书程序代码(答案)(实验三),个人原创,仅供参考与交流。 希望多多交流,共进步! 实验三 类对象 一、实验目的: 掌握Java类的结构、类的定义、方法属性的定义以及对象的实现; 掌握类及其成员修饰符的使用;掌握构造函数的使用;方法的参数传递返回值的用法; 掌握类变量与实例变量,以及类方法与实例方法的区别。 三、实验内容: 1.定义一个学生类(Student),属性有private的名字(name), public的年龄(age),专业(specialty)封装name属性的方法:setName(),getName(),getspecialty()编写Application,创建一个学生对象,设置nameage属性值,然后调用一个方法(此方法将对象作为参数传递,在方法中打印出学生的名字name年龄age)。(学生类仅包含静态成员变量方法。) 2.定义一个类Point,代表一个点,public属性有xy,方法有显示点坐标 show(),构造函数有两个参数分别给x,y赋值,在main方法中构造两个对象,再创建一方法(getMiddle)为取两个点构成线段的中点的坐标,参数为2个点对象,调用此方法后得到一个新的点,编写Application,显示该对象的坐标值。 3.定义一个复数(z=x+iy)类Complex,包含: 两个属性:实部x虚部y 默认构造函数 Complex(),设置x=0,y=0 构造函数:Complex(int i,int j) 显示复数的方法:showComp()将其显示为如: 5+8i或5-8i 的形式。 求两个复数的方法:(参数是两个复数类对象,返回值是复数类对象)public Complex addComp(Complex C1,Complex C2) 求两个复数的差的方法:(参数是两个复数类对象,返回值是复数类对象)public Complex subComp(Complex C1,Complex C2) 求两个复数的乘积的方法:(参数是两个复数类对象,返回值是复数类对象,新复数实部=两复数实部乘积-两复数虚部乘积,新复数虚部=两复数实部与虚部交叉乘积之,)public Complex multiComp(Complex C1,Complex C2) 比较两个复数是否相等的方法(参数是两个复数类对象,返回值是boolean类型)public boolean equalComp(Complex C1,Complex C2) 在Application中测试该类的方法,实部x虚部y可由main方法参数提供输入。 三、实验要求: 1. 正确地定义类、方法属性; 2. 学会方法的参数传递返回值的用法; 3. 熟练使用类及其成员修饰符 4.使用构造函数创建类的对象; 5. 类变量与实例变量,以及类方法与实例方法的使用 6.程序应包括各个被调用方法的执行结果的显示。 7.写出实验报告。要求记录编译执行Java程序当中的系统错误信息提示,并给出解决办法。(附运行界面、源代码)。 四、实验步骤: 1.(第1题)定义一个学生类(Student)及它的属性方法;定义主类main(),在main()方法中创建学生对象,并通过对象调用它的方法setName(),getName(),输出学生的名字name年龄age。 2. (第2题) 定义类Point及它的属性、方法构造函数,定义主类main(),在main()方法中创建两个坐标对象,,并通过对象调用getMiddle方法后得到一个新的点坐标,调用show()显示该对象的坐标值。 3. (第3题)定义一个复数(z=x+iy)类Complex,及它的属性、方法构造函数;定义主类main()方法,在main()方法中创建两个复数类Complex对象,并通过复数类对象调用它们的属性方法输出方法执行结果。 五、自做实验 1. 构造一个类来描述屏幕上的一个点,该类的构成包括点的xy两个坐标,以及一些对点进行的操作,包括:取得点的坐标值,对点的坐标进行赋值,编写应用程序生成该类的对象并对其进行操作。 2. 编写实现:有一个三角形类Triangle,成员变量有底边x另一条边y,两边的夹角a(0<a<180),a为静态成员,成员方法有两个:求面积s(无参数)修改角度(参数为角度)。 3. 编写实现: 构造函数为 Triangle(int xx,int yy,int aa) 参数分别为x,y,a赋值 在main方法中构造两个对象,求出其面积,然后使用修改角度的方法,修改两边的夹角,再求出面积值。(提示:求高的方法 h=y*Math.sin(a) ) 注意:构造方法用于对成员变量初始化,无参数的构造方法将成员变量初始化为0值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值