我的函数有以下问题,应该返回一个随机数。当我想通过调用该函数生成几个数字时,它们完全相同。如何解决在调用函数时始终返回相同数字的问题?我需要随机保持功能。
以下是代码:
with Ada.Numerics.discrete_Random
function generate_random_number ( n: in Positive) return Integer is
subtype Rand_Range is Integer range 0 .. n;
package Rand_Int is new Ada.Numerics.Discrete_Random(Rand_Range);
use Rand_Int;
gen : Rand_Int.Generator;
ret_val: Rand_Range;
begin
Rand_Int.Reset(gen);
ret_val := Random(gen);
return ret_val;
end;
答案 0 :(得分:2)
只有一个参数的Random
过程应该启动具有"时间相关状态"的随机数发生器。但是,如果它被连续快速调用一次,很可能是" time"程序使用的每次都是相同的,因为程序运行速度可能比时钟分辨率快。 (在delay 0.5
的两次使用之间尝试generate_random_number
之类的测试;很可能会得到两个不同的结果。)
无论如何,随机数生成器的预期用途是在其上使用Reset
一次设置种子,然后生成从种子开始的随机数序列。通过这样做,您还可以每次使用相同的种子,以获得可重复的随机数序列,以进行测试;或者你可以使用时间依赖的种子。但是,每次需要随机数时重置随机数生成器不是使用RNG的正常或推荐方式。因此,您需要将Reset
来电移出generate_random_number
。不幸的是,这也意味着即使n
参数在每次调用时都不同,您也必须使用相同的生成器,这意味着您可能被迫使用Float_Random
而不是Discrete_Random
。
PS 进一步研究,我在G.2.5中发现了这一点:"对时间相关复位程序的两次不同调用应将发生器重置为不同的状态,提供呼叫在时间上分开至少一秒,不超过五十年。" [强调我的。]我确信当你尝试它时,呼叫间隔不到一秒钟。
答案 1 :(得分:2)
随机生成器gen
不应该是函数的本地。目前,您正在每次generate_random_number
调用时重新创建它,并对其进行初始化,因此您总能获得相同的结果并不奇怪。
如果你让gen
- 例如 - 一个全局变量,初始化一次,那么每次使用它时你都会得到一个新的随机数。 (是的,全局变量很糟糕,但见下文)
不幸的是,这对于function generate_random_number ( n: in Positive)
的语义并不是特别好,它可以每次不同地限制随机数的范围。最简单的解决方案是使gen
返回任何有效的整数,并使用模运算为每次调用返回正确范围内的数字。这可行,但你应该知道它可能会引入加密的弱点,超出我的分析技能。
如果是这种情况,您将需要一种不同的方法,例如为您需要的每个范围创建不同的随机生成器;注意以不同方式播种(重置)它们,否则可能会再次出现加密漏洞,例如不同发生器之间的相关性。
现在全局变量的结构很差,因为任何语言的所有常见原因。因此,更好的方法是通过将其包装在包中来使其成为资源。
package RandGen is
function generate_random_number ( n: in Positive) return Positive;
end RandGen;
这就是所有客户需要看到的。该软件包实现如下:
with Ada.Numerics.discrete_Random;
package body RandGen is
subtype Rand_Range is Positive;
package Rand_Int is new Ada.Numerics.Discrete_Random(Rand_Range);
gen : Rand_Int.Generator;
function generate_random_number ( n: in Positive) return Integer is
begin
return Rand_Int.Random(gen) mod n; -- or mod n+1 to include the end value
end generate_random_number;
-- package initialisation part
begin
Rand_Int.Reset(gen);
end RandGen;
编辑:如果n远小于发电机范围,雅各布建议拒绝超出范围的值会更好但效率低。一个解决方案可能是创建几个生成器,让generate_random_number
函数选择覆盖0 ... N的那个,浪费最少。
答案 2 :(得分:0)
假设您在启动程序时可以确定上限:
包Random
(规范):
with Generic_Random;
with Upper_Limit_Function;
package Random is new Generic_Random (Upper_Limit => Upper_Limit_Function);
通用包Generic_Random
(规范):
generic
Upper_Limit : Positive;
package Generic_Random is
subtype Values is Natural range 0 .. Upper_Limit;
function Value return Values;
end Generic_Random;
通用包Generic_Random
(正文):
with Ada.Numerics.Discrete_Random;
package body Generic_Random is
package Random is new Ada.Numerics.Discrete_Random (Values);
Source : Random.Generator;
function Value return Values is
begin
return Random.Random (Source);
end Value;
begin
Random.Reset (Source);
end Generic_Random;