Ada随机数是相同的

时间:2014-11-06 17:50:17

标签: random ada

我的函数有以下问题,应该返回一个随机数。当我想通过调用该函数生成几个数字时,它们完全相同。如何解决在调用函数时始终返回相同数字的问题?我需要随机保持功能。

以下是代码:

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;

3 个答案:

答案 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;