求写一个随机函数(不是delphi自己带的那个)(50分)

  • 主题发起人 主题发起人 cmdline
  • 开始时间 开始时间
C

cmdline

Unregistered / Unconfirmed
GUEST, unregistred user!
求一个随机函数(不是delphi自己带的那个random)
昨天看了一点关于函数发生器的文章,所以想自己写一个但是却没有找到合适的方法。
有不有哪个高手写过这样的函数的?最好在后面还能给这个随机函数做一些验证
function Perrandom(I:Integer):Integer;
var
.......
begin
........
Result:=..... mod I;
.........
end;
这是自己想到的一部分,后面不知道该怎麽写?
 
你为什么不用系统带的那个啊
 
你要用系统代的,再做一些调整就可以了
例如他的范围
 
系统里的怎麽看函数源代码?
用ctrl按在random这个函数上,但是跳到system这个业面来了
还是没有找到这个random函数代码。
 
//Delphi中的random函数其实是system._RandInt函数才对,不过这个函数是内联汇编的,我现将他转成pascal的。
Function _Random(Value:LongWord):LongWord;
begin
RandSeed := RandSeed * $08088405 + 1
// RandSeed是system中的一个全局变量,这个变量的初始化代码在Randomize函数中。
result := DWORD(((UInt64(RandSeed) and $ffffffff) * (UInt64(Value) and $ffffffff)) shr 32);
end;

//发现转换错误,修改了一下贴子。
 
还有没有其他方法?
Function _Random(Value:LongWord):LongWord;
begin
RandSeed := RandSeed * $08088405 + 1
// RandSeed是system中的一个全局变量,这个变量的初始化代码在Randomize函数中。
result := DWORD(((UInt64(RandSeed) and $ffffffff) * (UInt64(Value) and $ffffffff)) shr 32);
end;
这个程序为什麽可以产生随机数?基于什麽原理?
UInt64(RandSeed) and $ffffffff这句怎麽解释?因为和ffffffff相与不就是其本身吗?
为什麽要写这一句
 
这个程序为什麽可以产生随机数?基于什麽原理?
[red]为什么可以产生随机数,基于什么原理,这个问题我也不懂,无法回答你。[/red]
UInt64(RandSeed) and $ffffffff这句怎麽解释?因为和ffffffff相与不就是其本身吗?
为什麽要写这一句
[red]那一句代码的作用是初始化清除int64大整数的高32位的数据。如果不这样做的话,64位的整数高32位可能带有未知的数值,会影响计算的结果。[/red]
 
[red]那一句代码的作用是初始化清除int64大整数的高32位的数据。
什麽意思,我不明白。
到底是清除还是初始化呢?
如果是清除的话,应该是下面这样写吧。
UInt64(RandSeed) and $0000ffff
如果是初始化的话,是指高32位全为1吗?
如果是这样,应该是下面这样写吧。
(UInt64(RandSeed) and $ffffffff) or $ffffffff
 
就是将一个64位的整数高32位清0,让这个64位的整数变成XXXXXXXXXXXXXXXX and $FFFFFFFF = 00000000XXXXXXXX
 
还有一个方法

生成一个guid
然后把每个字符变成int相加
然后再mod

即可完全达到你的要求.而且在sql server 中也可以通过此方法
实现一个真正的随机函数.

大家都知道,sqlserver中自带的随机函数是假的,生成的可都是一样的.[:(]
 
自己查了一下资料,RandSeed可以通过鼠标移动和键盘响应时间来确定,是一个随机数种子
不过还不知道怎麽在程序中,确定它是一个真正的随机函数。
 
看了半天还是不明白楼主心目中“真正的随机函数”应该是什么样的。
一般的高级语言都有自己内置的随机数发生器,这些发生器根据一个给定的种子以及特定
的算法产生“伪随机数列”,由于要满足效率和随机两方面的需求,随机数发生器的算法是
有讲究的(在一般情况下,即要“随机”,又要“可重现”,又不能太慢或者占用太多的存
储器资源),Delphi随机数发生器所采用的将位运算与MOD算子进行组合的算法就是非常经
典的一种。更加复杂的算法虽然在随机性方面会更加好(这是废话,越复杂的当然越显得
“随机”啦),但是所需要的时间和空间开销都会不可避免的增大,所以只在有特殊要求的
情况下由程序员自己编写。
在随机算法确定了以后,剩下的问题就是用来给随机数发生器的初始数据的来源了——由
于计算机运算的精确性和可再现性,即便是再复杂的算法,如果初始参数没有变化,那么无
论运行多少次,其结果(序列)都必然是相同的。有鉴于此,设置初始参数也就成了随机算
法中不可或缺的一环。由于程序运行的环境中绝大多数信息都不具备足够的随机性(比如机
器名、用户名、IP、Handle、内存地址等——它们都无法在多次调用时有足够的差别),为
了省事,Delphi的随机数发生器提供了一个利用系统时钟来初始化随机数种子的Ramdomize
过程——程序员也可以指定特定的数字赋予RandSeed全局变量来初始化随机数发生器。看看
Ramdomize的源码:
procedure Randomize;
var
Counter: Int64;
begin
if QueryPerformanceCounter(Counter) then
RandSeed := Counter
else
RandSeed := GetTickCount;
end;
——Delphi所做的就是利用高精度时钟(或者低精度的GetTickCount)来做为RandSeed罢
了。
现在可能存在的情况是:有使用随机数的程序中,从头到尾都没有Randomize过——其结
果就是每次运行都是“同样的随机”;有的程序则是在程序启动时进行一次性Randomize,
然后就没有再更改过种子;有的程序是在每次进入某个状态时进行初始化,而在该状态内没
有任何主动改变随机种子的动作(比如牌类游戏在每次发牌之前根据时钟初始化随机种子,
直到牌局结束,有的随机抽题考试也是这种模式)——其结果就是有可能被高手从已经得到
的伪随机序列反推出种子值从而预测之后的伪随机值(因为做为种子的时钟值的范围可以控
制在一个不大的范围内,然后利用相同算法的随机发生器进行穷举匹配)。
上面说了这么多,还是在普通的“可重现”随机数发生算法(即相同的初始值必然得到同
样的随机序列)的范畴内,如果楼主不需要可重现,那么可以利用定时器或者鼠标键盘事件
来做文章——每0.1秒或者MouseMove时都触发一次无用的Random调用,使得真正被用到的随
机数并不是“连续”获得的随机数,并且基本上不可能控制或者预测随机取数的间隔。
如果楼主需要更加“安全”的“非标准”随机数发生器(可重复的),网上有很多这类资
源,高抬贵手搜一下即可 :)
 
creation-zy兄
利用网络搜索,我早已搜索过
所有的随机数公式,都需要一个种子
兄台所谓的更加‘安全’的‘非标准’随机数发生器是什麽意思?
不需要种子吗?
至于我说的真正的随机数生成器,是通过结果统计来验证的。好像是通过中方方差来验证,但是在程序中怎麽写,我真的不知道。所以想问一下,这方面的东西。
 
既然是“通过结果统计来验证”,那么我以为Delphi自带的随机数发生器应该可以满足您
的需求——毕竟它的算法也是“久经考验”的了。
为什么要种子的原因我已经说了——真正的不确定性只会来自于非数字的物理世界,而计
算机程序算法无论多么复杂,都是“伪随机”的,但是,伪随机并不等于不可以被当成随机
信息源来使用。对于这些五花八门的随机数产生算法来说,相同的种子必然产生相同的随机
序列。例如:某算法用5做种子时,产生的结果序列为:1,0,8,3,9,5,0,2,...——无论在什
么情况下,只要种子是5,该算法都会得到同样的伪随机序列——但这里的“同样”并不是
说序列的相邻数字一样,而是你今天用5做种子得到了一个序列,明天也用5做种子得到一个
序列——这两个序列中相同位次的伪随机值必然是一样的。如果你希望每次的结果都尽可能
的不同,那么最省事的就是用当前系统时间做为种子——从Delphi源码中可以看出,Delphi
的Randomize使用了高精度定时器,两次初始化得到相同种子的概率小于百万分之一。
我说的“安全”,是针对那些敏感的、可能遭到破解的随机算法的,如果您的算法没有被
破解(高手有空破解一个软件的前提当然是有利可图,否则您就放心吧)的危险,那就无所
谓“安全”了。
刚才我提到了“伪随机”算法的定义,那么,真正随机的算法必然会使用到非数字化的物
理世界的信息——俺就写了几个,有的效率高(每秒钟几千个32Bit随机数),有的效率低
(好几秒生成几个)——他们共同的特点就是将物理世界做为种子,无需专门设置种子值,
具有绝对的不可重复性、不可预测性:P
下面是我使用在 http://www.delphibbs.com/delphibbs/dispq.asp?lid=1604583 中发布
的算法的随机结果(为了整齐,将整数使用16进制显示):
3835CF77 45CEFE4E 1F2FBD57 AE4501B2 9C5A0D4E D04AFB16 5CC282E4 02C6506A A1477931 3A20A6B4 F9113BDD 5205F905 12DC0B7F A69C3DA5 89E83887 65F647F7 01EE008C 9990DC61 B0662934 68165746 57315CB5 C9F33B7F D309B29C 3C154B13 8A34DDD1 13FA433C C404AD10 CBD518E6 EC7B9540 C1EEC30C DFDAEC9A F3470787 17FC557A 7963FFEE C306E6C8 A5A2C83B FCB5DA15 8E92C11A D2131F84 6B1CB27A 398F8BE0 24F38BFF A980D089 6A0E9161 3EF78F1D AB6F11E8 E4104B6D E2D51317 C3C1287F 7675A4E6 6B1B1FC3 66080BB0 726DBAF7 98DFF665 D5A92B85 0187D0E6 7CEA85FF 52164BD8 925846CC 17603BA3 E0D9F05B E2A8C54B 707B2672 2D72AE34 619F033F 40ADD195 6D48F8D9 FF3BEC01 C80E7C6E 1333A0E3 BA12DBFA A475C270 3619402B 8B8F91A4 CBB4E92F AA0E3650 96AC6760 63480E0B FD84AE0B EA695F1D 4F992F52 28F5DE60 9B25E2F1 93C5CBF6 0C810E67 28AEF628 A2A15A1A E4E85ED3 069D0559 274BF20B 8CAE6C5A 06FEEBAA 16EC9E42 C7A67C52 72091E33 2B4BF866 DC501981 8F1ABB1E 88345842 8750CDED
 
to: creation-zy兄
在那个多线程产生随机数的程序中,有些问题我不太懂,请指教
我在最后加了部分程序进行测试,发现RandRecord数组所产生的数全为0;
另外
for i:=1 to ThreadNumber do
begin
Inc(RandRecord[RecordInt mod ModNumber div (ModNumber div DivNumber)]);
-------------------------------------------------------------------------------
上面的东西是程序中的一段,RandRecord数组范围是200
而这里循环却只有六次,所以,我不太明白这个RandRecord数组拿来做什麽用?
另外,在密码学研究领域中,如果key取值太小,即使再随机也会被穷举掉

--------------------------------------------------------------------------------
 
建议楼主不要在“随机”和“伪随机”上过多的耗费精力。我推荐的真随机算法不是多线
程的版本(一是因为效率太低,还有就是对线程环境很敏感,有些线程实际上没有机会得到
执行),用 function GetARndNumber(HashRnd:Boolean):Integer 函数即可。

ps: 大段的贴另一个帖子的代码毫无意义(只会影响视线),建议把上面Copy的部分删除。
 
我就用系统的精确时间涵数 大概是:getickcount() 是精确到0.0001秒的, 然后用它取余就行
 
关于creation-zy推荐的那个硬盘读取随机
我看了
其中对delphi自带的函数的评价
那个我觉得不太好,因为使用randmoize用的是for循环
循环速度大于其种子采样速度
也就是说随机反而成了,比拼速度的感觉
 
晕,我什么时候推荐过硬盘读取了?——我在帖子里强调了文件读写存在的问题。而利用
CPU周期指令能够高效的得到足够随机的结果而无需任何形式的“种子”——这就够了。

另外,楼主似乎还不知道“真随机”和“伪随机”的本质差别所在,只是基于自己朴素而
模糊的认识,追求心中的目标——建议有多深的功夫干多好的事情,不要在一个非关键问题
上消耗太多,如果真的有精力,建议先找教科书系统的学习随机理论——有了扎实的理论基
础后再投入实践,遇到的困难就会少很多。
 
unit Unit1;
我写了个随机初始化数组,测试了一下还可以
interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
Image1: TImage;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
procedure Swap(var i:Integer;var j:Integer);
var
Temp:Integer;
begin
Temp:=i;
i:=j;
j:=Temp;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
S,K:array[0..255] of Integer;
I,J:Integer;
begin
for I:=0 to 255 do
S:=I;
Randomize;
for J:=0 to 255 do
begin
Randomize;
K[J]:=Random(256);
end;
for I:=0 to 255 do
begin
J:=(I+S+K)mod 256;
Swap(S,S[J]);
end;
Image1.Canvas.Brush.Color:=clYellow;
Image1.Canvas.FillRect(Rect(0,0,255,255));
for I:=0 to 255 do
begin
ListBox1.Items.Strings:=IntToStr(S);
Image1.Canvas.Pixels[I,S]:=clRed;
end;
end;

end.
 
后退
顶部