我想生成指定长度的随机数。
function _RandomCode(const CodeLen: Word): Word;
begin
Result := Random(CodeLen);
repeat
Result := Result + Random(CodeLen) + 1;
until (Length(IntToStr(Result)) = CodeLen)
end;
结果始终为10000
答案 0 :(得分: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使用a初始化内置随机数生成器 随机值(从系统时钟获得)。随机数 应该通过调用Randomize或者通过调用初始化生成器 为RandSeed分配一个值。
不要将循环中的Randomize调用与调用 随机功能。通常,Randomize在所有之前只调用一次 调用随机。
如果您将_RandomCodeStr
功能放在一个单独的单元中,则可以将Randomize
的呼叫置于该单元initialization
部分。
答案 1 :(得分: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 :(得分:1)
使用randomize
分开的两个音符(但只有一次!!!),如Tom Brunberg所指出的
1)Random不是加密安全的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代码!最好在功能内部进行一次。