我们生活的环境充满了随机性。一直以来运气,概率和命运这些概念都与随机性紧紧联系在一起。所有人类无法理解或无法预测的事物往往都被归类为随机事物。从生理上来说,我们也是沉浸在了随机海洋中。从云的运动到粒子和波浪的行为,随机性简直无处不在。 然而,尽管人类接触到了各种各样的随机事物,对随机性很熟悉,但依然难以将它转化为计算机可以使用的东西。当我们谈论计算机系统中的随机性时,我们真正指的是伪随机性,即尽可能模拟出现实世界应有的随机性,使之近乎于“真正的随机性”。以密码学安全伪随机数生成器为例,这是一个非常强大的随机性模拟。 随机数在隐私技术和密码学中发挥着重要作用。令人惊艳的是,通过生成一个随机数来对一条消息进行运算(XOR),提供了一种简单但十分强大的加密方案。即使是双方之间最简单的私人通信形式(即双方提前共享密钥的对称加密方案)也要求共享的密钥是随机的。如果此共享密钥不是随机的,则加密就毫无用处,因为任何知道密钥生成算法的人都可以确定密钥然后解密该条消息。 随机数的重要性不仅体现在安全通信渠道的建立上,还体现在确认通信对象上。如果多个人试图通过有限带宽的频道来互相通信,则可以利用随机数来确定频道携带消息的合理顺序。 随机数能够有效帮助团体或计算机达成一致协议或共识。区块链就是一个多方尝试就全局视角的某种更新达成一致(共识)的成功案例。更新通常在一轮内完成,也就是在一个周期性离散时间间隔内。 在互联网上,特定时间段内发送的消息数量是有上限的(即吞吐量或TPS),并且发送消息必将花去一定的时间( 即延迟),这都对共识造成了一定的限制。任何区块链共识协议的目标是在上述限制范围内达成一致协议。在公链上有数千个节点参与了区块链的维护,如果每个节点需要向所有其他节点发送消息并获得其反馈,那么网络的限制会大大增加达成共识的成本。这是因为在一轮时间内通过网络发送的消息数量太大。因此,为了确保共识,则需要通过减少在互联网上发送消息的数量来优化通信方案。 比特币达成此协议(中本聪共识)的方式是通过使用工作证明(PoW)作为随机数源来确定每一轮中哪一个区块将会被添加到区块链中,从而减少消息传递的费用。而WDC智慧链采用的DPOS(委托权益证明)协议,用于解决该问题的方法是根据持币者选择的15位代表(维护与管理区块链的节点),然后这些代表可以在网络限制内相互通信并及时达成一致。 为了公平选举出小组委员会的成员,保证没有人会提前知道成员的身份,WDC智慧链算法融入了无偏倚的随机数源。一旦该组验证者在两个区块上达成了一致,那个区块就会被广播给网络中的每一个人。 下面介绍几种简单的随机数的算法 1、 生成随机数 一般c语言中提供了随机数生成函数, 其一是伪随机数–rand:用于返回一个0-32767之间的伪随机数; 其二是随机种子函数–srand:用来初始化随机数发生器的随机种子 #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int i,j; srand((int)time(0)); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { printf("%d ?",rand()); } printf("\n"); } return 0; } 当然也可以生成一定范围内的随机数,比如生成0——100之间的随机数。 #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int i,j; srand((int)time(0)); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { printf("%d ?",rand()*100/32767); } printf("\n"); } return 0; } 也可以生成100——200之间的随机数 #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int i,j; srand((int)time(0)); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { printf("%d ?",rand()/1000+100); } printf("\n"); } return 0; } 使用rand()函数获取一定范围内的一个随机数,如果想要获取在一定范围内的数的话,直接做相应的除法取余即可。 #include<iostream> #include<ctime> using namespace std; int main() { srand(time(0)); for(int i=0;i<10;i++) { //产生10以内的整数 cout<<rand()%10<<endl; } } 2 、生成[0,1]之间均匀分布的随机数算法 ri=mod(a?ri?1+b,base) pi=ri/base 在这里采用第二种方式生成随机数。其中i=1,2,3.。。。而pi就是地推倒的第i个随机数,根据经验,一般选取基数base=256.0,一般为2的整数倍;另外的两个常数选取a=17.0 和b=139.0,需要注意: (1)这里的取模运算是针对浮点型数据的,而c语言中的取模运算不能用于浮点数数据的操作,这样就需要用户自己编写取模的程序; (2)ri是随着递推而每次更新的。因此,如果将这个算法编写出函数,需要考虑参数是传值还是传地址; 递推更新,所以在这里要传地址,否则得不到结果! #include <stdio.h> double rand0_1(double *r) { double base=256.0; double a=17.0; double b=139.0; double temp1=a*(*r)+b; //printf("%lf",temp1); double temp2=(int)(temp1/base); //得到余数 double temp3=temp1-temp2*base; //printf("%lf\n",temp2); //printf("%lf\n",temp3); *r=temp3; double p=*r/base; return p; } int main() { double r=5.0; printf("output 10 number between 0 and 1:\n"); for (int i = 0; i < 10; i++) { printf("%10.5lf\n",rand0_1(&r)); } return 0; } 3 、产生任意范围内的随机数 比如产生[m,n]之间的随机数,这个很容易,只要将之前的[0,1]之间的随机数这样处理就行了,m+(m-n)*rand0_1(&r)就行了。 #include <stdio.h> double rand0_1(double *r) { double base=256.0; double a=17.0; double b=139.0; double temp1=a*(*r)+b; //printf("%lf",temp1); double temp2=(int)(temp1/base); //得到余数 double temp3=temp1-temp2*base; //printf("%lf\n",temp2); //printf("%lf\n",temp3); *r=temp3; double p=*r/base; return p; } int main() { double m=1.0,n=5.0; double r=5.0; printf("output 10 number between 0 and 1:\n"); for (int i = 0; i < 10; i++) { printf("%10.5lf\n",m+(n-m)*rand0_1(&r)); } return 0; } 4、正态分布的随机数生成算法 符合正太分布的随机数在研究中也很重要,下面给出一种生成正态分布数的方法 random_normality=u+σ(∑Ri)?n/2n/12????√ 其中Ri表示[0,1]之间均匀分布的随机数;u为均值,σ2为方差,当n趋向于无穷大的时候,得到随机的随机分布为正态分布; #include <stdio.h> #include <math.h> double rand0_1(double *r) { double base=256.0; double a=17.0; double b=139.0; double temp1=a*(*r)+b; //printf("%lf",temp1); double temp2=(int)(temp1/base); //得到余数 double temp3=temp1-temp2*base; //printf("%lf\n",temp2); //printf("%lf\n",temp3); *r=temp3; double p=*r/base; return p; } double random_normality(double u,double t,double *r ,double n) { double total=0.0; double result; for (int i = 0; i < n; i++) { total+=rand0_1(r); } result=u+t*(total-n/2)/sqrt(n/12); return result; } int main() { double r=5.0; double u=2.0; double t=3.5; double n=12; printf("output 10 number between 0 and 1:\n"); for (int i = 0; i < 10; i++) { printf("%10.5lf\n",random_normality(u,t,&r,n)); } return 0; } 补充知识点:leveldb中使用了一个简单的方式来实现随机化数;算法的核心是seed_ =(seed_ * A) % M,下面把源代码贴出来,不难,可以和上面的参考下 private: uint32_t seed_; public: explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { // Avoid bad seeds. if (seed_ == 0 || seed_ == 2147483647L) { seed_ = 1; } } uint32_t Next() { static const uint32_t M = 2147483647L; ??// 2^31-1 static const uint64_t A = 16807; ?// bits 14, 8, 7, 5, 2, 1, 0 // We are computing // ??????seed_ = (seed_ * A) % M, ???where M = 2^31-1 // // seed_ must not be zero or M, or else all subsequent computed values // will be zero or M respectively. ?For all other values, seed_ will end // up cycling through every number in [1,M-1] uint64_t product = seed_ * A; // Compute (product % M) using the fact that ((x << 31) % M) == x. seed_ = static_cast<uint32_t>((product >> 31) + (product & M)); // The first reduction may overflow by 1 bit, so we may need to // repeat. ?mod == M is not possible; using > allows the faster // sign-bit-based test. if (seed_ > M) { seed_ -= M; } return seed_; } // Returns a uniformly distributed value in the range [0..n-1] // REQUIRES: n > 0 uint32_t Uniform(int n) { return Next() % n; } // Randomly returns true ~"1/n" of the time, and false otherwise. // REQUIRES: n > 0 bool OneIn(int n) { return (Next() % n) == 0; } // Skewed: pick "base" uniformly from range [0,max_log] and then // return "base" random bits. ?The effect is to pick a number in the // range [0,2^max_log-1] with exponential bias towards smaller numbers. uint32_t Skewed(int max_log) { return Uniform(1 << Uniform(max_log + 1)); } }; 总之,做个简单的总结 C语言/C++怎样产生随机数:这里要用到的是rand()函数, srand()函数,和time()函数。 需要说明的是,iostream头文件中就有srand函数的定义,不需要再额外引入stdlib.h;而使用time()函数需要引入ctime头文件。 使用rand()函数获取一个随机数 如果你只要产生随机数而不需要设定范围的话,你只要用rand()就可以了:rand()会返回一随机数值, 范围在0至RAND_MAX 间。RAND_MAX定义在stdlib.h, 其值为2147483647。 使用rand函数和time函数 我们上面已经可以获取随机数了,为什么还需要使用time函数呢?我们通过多次运行发现,该程序虽然生成了10个随机数,但是这个10个随机数是固定的,也就是说并不随着时间的变化而变化。 这与srand()函数有关。srand()用来设置rand()产生随机数时的随机数种子。在调用rand()函数产生随机数前,必须先利用srand()设好随机数种子(seed), 如果未设随机数种子, rand()在调用时会自动设随机数种子为1。 上面的例子就是因为没有设置随机数种子,每次随机数种子都自动设成相同值1 ,进而导致rand()所产生的随机数值都一样。 srand()函数定义 :void srand (unsigned int seed); 通常可以利用geypid()或time(0)的返回值来当做seed 如果你用time(0)的话,要加入头文件#include time(0)或者time(NULL)返回的是系统的时间(从1970.1.1午夜算起),单位:秒 参考:随机数生成算法 (https://www.cnblogs.com/ECJTUACM-873284962) —- 编译者/作者:智慧链技术社区 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
区块链中随机数的实现
2020-03-16 智慧链技术社区 来源:区块链网络
LOADING...
相关阅读:
- 蚂蚁的追赶者——腾讯区块链2020-07-31
- 区块链商业思维如何助力链改?2020-07-31
- MYC智能矿机来袭挖矿币再起风云之争2020-07-31
- 和东北大哥聊密码学终于懂了2020-07-31
- 恶意软件使用Dogecoin区块链进行隐藏的加密货币挖矿2020-07-31