2016-05-23 124 views
1

我想生成指定长度的随机数。delphi生成随机PIN码

function _RandomCode(const CodeLen: Word): Word; 
begin 
    Result := Random(CodeLen); 
    repeat 
    Result := Result + Random(CodeLen) + 1; 
    until (Length(IntToStr(Result)) = CodeLen) 
end; 

结果总是10000

+1

可能的重复的[在delphi中生成随机数](http://stackoverflow.com/questions/34481987/generate-random-number-in-delphi) –

+1

如果codelen是,比方说,4.会返回一个值0007可以接受吗?即7个前导零。或者你只在1000到9999之间寻找数字? –

+1

随机(4)可以是0,1,2或3.为什么不简单:'Result:= Random(IntPow(10,CodeLen));'? –

回答

6

虽然我投票决定关闭这个问题作为一个重复,再一想这里有问题,使得它不同于纯粹的随机函数应用程序。

首先,你的代码不给你期待的结果,因为你是添加小数字(0 .. codelen-1)的结果每个循环中,当值达到的值停止的是,当转换为字符串时,包含codelen个字符。对于codelen = 5,这将始终停止在10000 .. 10003.如果您要在调试器中加入代码,您很快就会意识到为什么您获得了您所做的结果。其次,在@MichaelVincent的启发下,PIN码通常允许前导零,f.ex。 '0123'。因此,我也认为在这个问题上也是如此。因为整型结果不能保存前导零,所以我建议你使用string型结果。

只在应用程序启动时调用Randomize一次。

function _RandomCodeStr(const CodeLen: Word): string; 
var 
    n: integer; 
begin 
    SetLength(Result, CodeLen); 
    for n := 1 to CodeLen do 
    Result[n] := Char(ord('0')+ Random(10)); 
end; 

我改变了函数的名称以反映它返回一个字符串。


添加对请求:

关于Randomize函数(或分配RandSeed)。它在文档中有解释:

随机初始化内置随机数发生器,随机值为 (从系统时钟获得)。随机数 生成器应通过调用Randomize或 赋值给RandSeed来初始化。

不要将调用与随机函数的调用结合起来调用随机函数,并调用 随机函数。通常,在调用Random之前,只调用一次Randomize。

如果你把_RandomCodeStr功能在一个单独的单元,你可以把呼叫Randomize在单位initialization部分。

+0

你拿起了我在我的评论问题中得到的东西:D –

+0

你能解释为什么我应该在应用程序启动时调用'Randomize'而不是在函数本身内调用它。因为我想把这个功能放在单独的单元中,每当我需要它时调用它,并且在每个应用程序中摆脱调用'Randomize' – RepeatUntil

+0

@RepeatUntil我编辑了有关'Randomize'的回答,以及如何在您计划的单元中调用一次把它塞进去。 –

1

除了使用randomize(但只有一次!)为指向的汤姆Brunberg

1)随机两点需要注意是不是密码安全PRNG,所以用它产生随机(如在不可预知的情况下)PIN码是相当不恰当的想法。

2)你的循环速度慢,甚至不太安全(通过连续多次调用Random,导致其统计量累积降低随机性)。 它可能是不确定的。如果一个时刻的长度会比CodeLen多?它永远不会缩小,循环永远不会结束;直到至少整数边界绕回。

使之显得有些更好的,你可以那样做:

function _PseudoRandomCode(const CodeLen: Word): Word; 
var s: string; i: integer; c: char; 
begin 
    SetLength(s, CodeLen); 
    for i := 1 to CodeLen do begin 
    c := '0'; 
    Inc(c, random(10)); // + 0..9 
    s[i] := c; 
    end; 
    Result := StrToInt(s); 
end; 

或类似的

function _PseudoRandomCode(const CodeLen: Word): Word; 
var i,j: integer; 
begin 
    i := 1; // 10^0 
    for j := 1 to CodeLen do 
     i := 10 * i; 
    // now i = 10^(CodeLen+1) that is '1' and CodeLen of zeroes. 

    Result := Random(i); 
end; 

虽然我会更好地使返回string值不word值的函数。

function _PseudoRandomCode(const CodeLen: Word): String; 
var s: string; i: integer; c: char; 
begin 
    SetLength(s, CodeLen); 
    for i := 1 to CodeLen do begin 
    c := '0'; 
    Inc(c, random(10)); // + 0..9 
    s[i] := c; 
    end; 
    Result := s; 
end; 

function _PseudoRandomCode(const CodeLen: Word): string; 
var i,j: integer; 
begin 
    i := 1; // 10^0 
    for j := 1 to CodeLen do 
     i := 10 * i; 
    // now i = 10^(CodeLen+1) that is '1' and CodeLen of zeroes. 

    Result := IntToStr(Random(i)); 
    if Length(Result) < CodeLen then 
    Result := StringOfChar('0', CodeLen - Length(Result)) + Result; 
end; 

你会做什么,例如_RandomCode(4) = 25?您将不得不在该功能以外的任何位置使用零填充PIN码!最好在功能内进行一次。

+1

在第二个代码中,对于Codelen,j:= 0似乎是一次太多。使用'codelen = 1''i'将变为100,IOW,返回值为0 .. 99 –

+0

@TomBrunberg正确。固定。 –

3

您的代码失败的原因:您要添加较小的值(1..5),直到数字位数达到5为止。总是得到10000的原因是您在启动时从未调用过Randomize。这意味着你的“随机”系列总是一样的。

使用RandomRange代替:

返回指定范围内的随机整数。

RandomRange返回从AFrom和ATo(非包含)之间延伸的范围内的随机整数。 RandomRange可以处理负范围(其中AFrom大于ATo)。

要初始化随机数生成器,请在调用RandomRange之前添加一个调用Randomize或将值分配给RandSeed变量。

function _RandomCode(const CodeLen: Word): Cardinal; 
// CodeLen is 1,2,3 etc. 
begin 
    Result := RandomRange(0,Trunc(IntPower(10,CodeLen))); 
end; 

我假定前导零是在PIN码可以接受的,否则所述第一参数设定为适当的值(IntPower(10,CodeLen-1))。

要转换一些固定长度和可能的前导零的字符串,使用:

Format('%.*d',[CodeLen,_RandomCode(CodeLen)]) 
+2

“Random”返回一个整数X,比如0 <= X

+2

有些问题:'Random(intvalue)'给出整数; RandomRange不包括ATo,所以'-1'是多余的;作者一定要'Codelen = 1,2,3,4,5',而不是十个权力。 – MBo

+1

CodeLen其实不是CodeLen,更好的计算方法是 –