C# 数据库随机抽取数据

C# 数据库随机抽取数据,第1张

我这只是思路啊,这个要实现的话要使用多线程技术
一个线程负责产生随机数与抽取数据
1首先一个随机数
对比内变量里的随机数,是否有重复,如果重复则此次无效,重新生成
2,根据此随机数抽取数据库中数据。
另一个线程负责清空内存变量的数据
即此线程开着一个计时器,然后根据时间来清除数据
希望对你有所帮助

如果要一串不重复的随机数的话,那这样是不行的。
比较好的方法是这样
先定义一个数组,比较100个。
随机提取两个数进行交换
重复次数多一点,比如说200次
现在这个数组就是一个随机的不重复的1到100的数组了。

产生随机数有多种不同的方法。这些方法被称为随机数发生器。随机数最重要的特性是:它所产生的后面的那个数与前面的那个数毫无关系。 真正的随机数是使用物理现象产生的:比如掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等等。这样的随机数发生器叫做物理性随机数发生器,它们的缺点是技术要求比较高。 在实际应用中往往使用伪随机数就足够了。这些数列是“似乎”随机的数,实际上它们是通过一个固定的、可以重复的计算方法产生的。计算机或计算器产生的随机数有很长的周期性。它们不真正地随机,因为它们实际上是可以计算出来的,但是它们具有类似于随机数的统计特征。这样的发生器叫做伪随机数发生器。 在真正关键性的应用中,比如在密码学中,人们一般使用真正的随机数。

参考资料:

>公式:(上限 - 下限 + 1 ) * rand() - 下限
介绍:John von Neumann说:Any one who considers arithmetical methods of producing random digits is , of course, in a state of sin
所以,在讨论算法实现随机数的时候,总是说“伪随机数”。
现在,应用最广的随机数生成算法是由Derrick Henry Lehmer1951年给出的线性同余法:
Xn+1 = ( aXn + c ) mod m, n>=0
在上一篇伪随机数的论述中,并没有给出X0, a, c, m的取值规则,只是给出了ANSI C和Microsoft Visual C++的实现。
在这儿我们可以自己先思考一下,我们期望从上式中得到的随机数应该满足:
1) 上式的输出足够随机,这是最基本的要求;
2) 上式给出尽量多的输出,越接近m个越好(不可能超过m),即周期尽量长,最好为m,这样才能保证上式满足均匀分布(m个数在周期m中各出现一次);
3) 上式的生成速度足够快。
最容易想到的,m的取值为计算机字大小(如2^32或2^64)。
但是这儿有个很严重的问题:Xn低位的随机性很弱。原因如下:
令d|m, 且
Yn = Xn mod d

Yn+1 = ( ( aXn + c ) mod m ) mod d
= ( aYn + c ) mod d
上述表达式的意义即:Yn为Xn低k位(d=2^k),这样的Yn序列形成周期为d甚至更短的同余序列。举例说明:d为2^1时,Yn为Xn的最低位(可假定为1或0),若Yn+1 != Yn,则Yn+2 == Yn必定成立,仅当a、c皆为奇数时Yn、Yn+1将0、1交替,否则,为常数(0或1)。
暂时抛开随机性不管,先找到周期为m的随机序列中的取值规则。
Donald Knuth在The Art of Computer Programming, Volume 2: Seminumerical Algorithms中的3212节对m, a, c和X0取值规则的表述:
1) gcd(c, m) = 1 即c, m互素,再白一点,c, m除1之外没有其他公因子;
2) 任给质数p, p|m ==> p|(a-1) 即m%p==0,则(a-1)%p==0。
3) 4|m ==> 4|(a-1) 即m%4==0,则(a-1)%4==0。
这个证明过程对于我这样的数论基础不是很扎实的搞应用技术的人来说有点难以理解了。有兴趣的话,还是去看3212的证明吧:-)。
上面的规则告诉我们,满足了上述规则后,可以保证序列周期为m。对于前面提到的关于随机性的问题,既然Xn低位的随机性比较弱,可以只取Xn的高位作为输出。高位的随机性和统计意义由a, c确定,其取值涉及统计检验,具体的也还是看33吧。
这篇文章解决了具有统计意义的随机数的部分理论问题。
PS: 之前曾经BS过Windows Live Writer,当时觉得Writer编辑功能太少,不能直接设定链接文字的字体颜色,知道CSS可以设定之后,又觉得Word 2007编辑的Blog转成html之后太大,而且也知道Word 2007上面是可以设置链接的target为_blank的。现在发现Writer还是很不错的了,原来是可以设定格式的,也可以直接编辑html,而且可以Web预览,链接还可以加入到链接词汇表,挺方便的。

撰文 | Bob Yirka

翻译 | 张宇哲

审校 | 董子晨曦

许多年来,计算机科学家一直在寻找一种能够生成真随机数的方法。但由于硬件水平的限制,大多数家用和商用电脑中的随机数生成器远达不到“随机”的标准。生成随机数之所以重要,是因为它构成了密码学的基础。在计算力足够的前提下,黑客能够破解这些由伪随机数编码的信息。与我们所处的自然世界不同,量子世界中存在许多真随机事件,例如不可预测的光子行为。

来自英国、德国和俄罗斯的一支研究团队利用量子力学的不可预测性,制造了一部能够生成真随机数的装置。在发表于《物理评论快报》的论文中,他们描述了借助量子理论,开发了一款真随机数生成器。
一种分束器,1:入射光;2: 50%透射光;3: 50%反射光。@ Tamasflex,wikimedia

该团队制造的装置由一个通用分束器组成,分束器一个输入端为激光,另一输入端则为空(即零信号)。随后,他们利用两个独立的探测器测量出射光束。在这套装置,每个到达分束器的光子被透射或被反射的概率相等,这意味着两个测量结果间的差值是不可预测的。因此,这一差值便是真“随机”的。
研究人员通过测量了光子在到达分束器之前的状态,进一步推进了这一研究。测量结果证实了由该设备产生的数据的确是随机的。最终,他们制造出的设备能够以每秒805千兆比特的速度生成随机数,且每组数据都证实是实时且随机的。值得一提的是,该设备使用的全部是现有的技术。

原文链接:

>看一下我博客里的一篇文章:
首先需要声明的是,计算机不会产生绝对随机的随机数,计算机只能产生“伪随机数”。其实绝对随机的随机数只是一种理想的随机数,即使计算机怎样发展,它也不会产生一串绝对随机的随机数。计算机只能生成相对的随机数,即伪随机数。
伪随机数并不是假随机数,这里的“伪”是有规律的意思,就是计算机产生的伪随机数既是随机的又是有规律的。怎样理解呢?产生的伪随机数有时遵守一定的规律,有时不遵守任何规律;伪随机数有一部分遵守一定的规律;另一部分不遵守任何规律。比如“世上没有两片形状完全相同的树叶”,这正是点到了事物的特性,即随机性,但是每种树的叶子都有近似的形状,这正是事物的共性,即规律性。从这个角度讲,你大概就会接受这样的事实了:计算机只能产生伪随机数而不能产生绝对随机的随机数。
那么计算机中随机数是怎样产生的呢?有人可能会说,随机数是由“随机种子”产生的。没错,随机种子是用来产生随机数的一个数,在计算机中,这样的一个“随机种子”是一个无符号整形数。那么随机种子是从哪里获得的呢?
下面看这样一个C程序:
//rand01c
#include<dosh>
static unsigned int RAND_SEED;
unsigned int random(void)
{
RAND_SEED=(RAND_SEED123+59)%65536;
return(RAND_SEED);
}
void random_start(void)
{
int temp[2];
movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);
RAND_SEED=temp[0];
}
main()
{
unsigned int i,n;
random_start();
for(i=0;i<10;i++)
printf("%u\t",random());
printf("\n");
}
这个程序(rand01c)完整地阐述了随机数产生的过程:
首先,主程序调用random_start()方法,random_start()方法中的这一句我很感兴趣:
movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);
这个函数用来移动内存数据,其中FP_SEG(far pointer to segment)是取temp数组段地址的函数,FP_OFF(far pointer to offset)是取temp数组相对地址的函数,movedata函数的作用是把位于0040:006CH存储单元中的双字放到数组temp的声明的两个存储单元中。这样可以通过temp数组把0040:006CH处的一个16位的数送给RAND_SEED。
random用来根据随机种子RAND_SEED的值计算得出随机数,其中这一句:
RAND_SEED=(RAND_SEED123+59)%65536;
是用来计算随机数的方法,随机数的计算方法在不同的计算机中是不同的,即使在相同的计算机中安装的不同的 *** 作系统中也是不同的。我在linux和windows下分别试过,相同的随机种子在这两种 *** 作系统中生成的随机数是不同的,这说明它们的计算方法不同。
现在,我们明白随机种子是从哪儿获得的,而且知道随机数是怎样通过随机种子计算出来的了。那么,随机种子为什么要在内存的0040:006CH处取?0040:006CH处存放的是什么?
学过《计算机组成原理与接口技术》这门课的人可能会记得在编制ROM BIOS时钟中断服务程序时会用到Intel 8253定时/计数器,它与Intel 8259中断芯片的通信使得中断服务程序得以运转,主板每秒产生的182次中断正是处理器根据定时/记数器值控制中断芯片产生的。在我们计算机的主机板上都会有这样一个定时/记数器用来计算当前系统时间,每过一个时钟信号周期都会使记数器加一,而这个记数器的值存放在哪儿呢?没错,就在内存的0040:006CH处,其实这一段内存空间是这样定义的:
TIMER_LOW DW ;地址为 0040:006CH
TIMER_HIGH DW ;地址为 0040:006EH
TIMER_OFT DB ;地址为 0040:0070H
时钟中断服务程序中,每当TIMER_LOW转满时,此时,记数器也会转满,记数器的值归零,即TIMER_LOW处的16位二进制归零,而TIMER_HIGH加一。rand01c中的
movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);
正是把TIMER_LOW和TIMER_HIGH两个16位二进制数放进temp数组,再送往RAND_SEED,从而获得了“随机种子”。
现在,可以确定的一点是,随机种子来自系统时钟,确切地说,是来自计算机主板上的定时/计数器在内存中的记数值。这样,我们总结一下前面的分析,并讨论一下这些结论在程序中的应用:
1随机数是由随机种子根据一定的计算方法计算出来的数值。所以,只要计算方法一定,随机种子一定,那么产生的随机数就不会变。
看下面这个C++程序:
//rand02cpp
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
unsigned int seed=5;
srand(seed);
unsigned int r=rand();
cout<<r<<endl;
}
在相同的平台环境下,编译生成exe后,每次运行它,显示的随机数都是一样的。这是因为在相同的编译平台环境下,由随机种子生成随机数的计算方法都是一样的,再加上随机种子一样,所以产生的随机数就是一样的。
2只要用户或第三方不设置随机种子,那么在默认情况下随机种子来自系统时钟(即定时/计数器的值)
看下面这个C++程序:
//rand03cpp
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
srand((unsigned)time(NULL));
unsigned int r=rand();
cout<<r<<endl;
return 0;
}
这里用户和其他程序没有设定随机种子,则使用系统定时/计数器的值做为随机种子,所以,在相同的平台环境下,编译生成exe后,每次运行它,显示的随机数会是伪随机数,即每次运行显示的结果会有不同。
3建议:如果想在一个程序中生成随机数序列,需要至多在生成随机数之前设置一次随机种子。
看下面这个用来生成一个随机字符串的C++程序:
//rand04cpp
#include<iostream>
#include<timeh>
using namespace std;
int main()
{
int rNum,m=20;
char ch=new char[m];
for ( int i = 0; i<m; i++ ){
//大家看到了,随机种子会随着for循环在程序中设置多次
srand((unsigned)time(NULL));
rNum=1+(int)((rand()/(double)RAND_MAX)36); //求随机值
switch (rNum){
case 1: ch[i]='a';
break ;
case 2: ch[i]='b';
break ;
case 3: ch[i]='c';
break ;
case 4: ch[i]='d';
break ;
case 5: ch[i]='e';
break ;
case 6: ch[i]='f';
break ;
case 7: ch[i]='g';
break ;
case 8: ch[i]='h';
break ;
case 9: ch[i]='i';
break ;
case 10: ch[i]='j';
break ;
case 11: ch[i]='k';
break ;
case 12: ch[i]='l';
break ;
case 13: ch[i]='m';
break ;
case 14: ch[i]='n';
break ;
case 15: ch[i]='o';
break ;
case 16: ch[i]='p';
break ;
case 17: ch[i]='q';
break ;
case 18: ch[i]='r';
break ;
case 19: ch[i]='s';
break ;
case 20: ch[i]='t';
break ;
case 21: ch[i]='u';
break ;
case 22: ch[i]='v';
break ;
case 23: ch[i]='w';
break ;
case 24: ch[i]='x';
break ;
case 25: ch[i]='y';
break ;
case 26: ch[i]='z';
break ;
case 27:ch[i]='0';
break;
case 28:ch[i]='1';
break;
case 29:ch[i]='2';
break;
case 30:ch[i]='3';
break;
case 31:ch[i]='4';
break;
case 32:ch[i]='5';
break;
case 33:ch[i]='6';
break;
case 34:ch[i]='7';
break;
case 35:ch[i]='8';
break;
case 36:ch[i]='9';
break;
}//end of switch
cout<<ch[i];
}//end of for loop
cout<<endl;
return 0;
}
而运行结果显示的随机字符串的每一个字符都是一样的,也就是说生成的字符序列不随机,所以我们需要把srand((unsigned)time(NULL)); 从for循环中移出放在for语句前面,这样可以生成随机的字符序列,而且每次运行生成的字符序列会不同(呵呵,也有可能相同,不过出现这种情况的几率太小了)。
如果你把srand((unsigned)time(NULL));改成srand(2);这样虽然在一次运行中产生的字符序列是随机的,但是每次运行时产生的随机字符序列串是相同的。把srand这一句从程序中去掉也是这样。
此外,你可能会遇到这种情况,在使用timer控件编制程序的时候会发现用相同的时间间隔生成的一组随机数会显得有规律,而由用户按键command事件产生的一组随机数却显得比较随机,为什么?根据我们上面的分析,你可以很快想出答案。这是因为timer是由计算机时钟记数器精确控制时间间隔的控件,时间间隔相同,记数器前后的值之差相同,这样时钟取值就是呈线性规律的,所以随机种子是呈线性规律的,生成的随机数也是有规律的。而用户按键事件产生随机数确实更呈现随机性,因为事件是由人按键引起的,而人不能保证严格的按键时间间隔,即使严格地去做,也不可能完全精确做到,只要时间间隔相差一微秒,记数器前后的值之差就不相同了,随机种子的变化就失去了线性规律,那么生成的随机数就更没有规律了,所以这样生成的一组随机数更随机。这让我想到了各种晚会的抽奖程序,如果用人来按键产生幸运观众的话,那就会很好的实现随机性原则,结果就会更公正。
最后,我总结两个要点:
1计算机的伪随机数是由随机种子根据一定的计算方法计算出来的数值。所以,只要计算方法一定,随机种子一定,那么产生的随机数就是固定的。
2只要用户或第三方不设置随机种子,那么在默认情况下随机种子来自系统时钟。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/13402919.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-29
下一篇 2023-07-29

发表评论

登录后才能评论

评论列表(0条)

保存