Discrete Random Number generation, via an iterate, or next; not via loop

Hi;

A question about how to generate a Discrete Random Number in a functional manner. I want a “next” operator for a random number. There’s plenty of examples of how to generate a sequence of pseudo-random numbers, but I don’t want them all immediately. I don’t think I’m explaining my problem very well. I may have zero or more intermediary actions between new random number requests. I guess you could say that I want a random number randomly :slight_smile:

Thanks in advance,
Retired Build Engineer

with Ada.Numerics.Discrete_Random;
with Ada.Text_IO;

procedure Example is
    package Integer_Random is new Ada.Numerics.Discrete_Random (Integer);
    Gen : Integer_Random.Generator;
    N : Integer;
begin
    Integer_Random.Reset (Gen, 42); --  maybe find a better way to seed. Ada.Calendar.Clock?
    N := Integer_Random.Random (Gen);
    Ada.Text_IO.Put_Line (N'Image);
end Example;

As long as you have the Gen object visible, you can call Integer_Random.Random (Gen) anytime to get a number.

Does that do what you want?

Hi Jeremy;

Thank you for some nice code which generates a sequence of discrete random numbers.

However, I don’t think that this will work as I’m trying to call for a random number from a routine. I gues that is called an “out-of-band” process (??)

I have three actions, only one of which needs a random number, but these actions can occur in any order (eg: A, B, C or A, A, C, B, C) where only action “B” needs a random number.

I’m trying to solve a Rosetta Code Task in Ada using the solution written in Go.

Here’s my code so far (still needs lots of work, even without the Randome Number Generator portion; it doesn’t compile yet, working out the issues):

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Numerics.Discrete_Random;

procedure Two_Bullet_Roulette is

  Number_of_Cylinders : constant Positive := 6;
  type Revolver_Cylinder_Array is array (1 .. Number_of_Cylinders) of Boolean;

  procedure Rshift (Cylinder : in out Revolver_Cylinder_Array) is
    Temp : Boolean := Cylinder (Number_of_Cylinders);
  begin
    for I in reverse 1..(Number_of_Cylinders-1) loop
      Cylinder (I+1) := Cylinder (I);
    end loop;
    Cylinder (1) := Temp;
  end Rshift;

  procedure Unload (Cylinder : in out Revolver_Cylinder_Array) is
  begin
    for I in Cylinder'Range loop
      Cylinder (I) := False;
    end loop;
  end Unload;

  procedure Load (Cylinder : in out Revolver_Cylinder_Array) is
  begin
    while (Cylinder (1)) loop
      Rshift (Cylinder);
    end loop;
    Cylinder (1) := True;
    Rshift (Cylinder);
  end Load;

 procedure Spin (Cylinder : in out Revolver_Cylinder_Array) is
    Random_Number : Natural := 11; -- need a functional style random number generator (SIGH)
  begin
    for I in 1..Random_Number loop
      Rshift (Cylinder);
    end loop;
  end Spin;

  function Fire (Cylinder : in out Revolver_Cylinder_Array) return Boolean is
    Shot : Boolean := Cylinder (1);
  begin
    Rshift (Cylinder);
    return Shot;
  end Fire;

  function Method (M : Character; Cylinder : in out Revolver_Cylinder_Array) return Natural is
  begin
    Unload (Cylinder);
    case M is
      when 'L' => Load (Cylinder);
      when 'S' => Spin (Cylinder);
      when 'F' => if Fire (Cylinder) then return 1; else return 0; end if;
      when others => null;
    end case;   
    return 0;
  end Method;

  function Display_Action (S : String) return String is  
    Display_String : Unbounded_String := Null_Unbounded_String;
  begin
    for I in S'Length loop
      case Slice (S, I, I) is
        when "L" => Append (Display_String, "load");
        when "S" => Append (Display_String, "spin");
        when "F" => Append (Display_String, "fire");
      end case;
      Append (Display_String, ", ");
    end loop;
    return To_String (Display_String);
  end Display_Action;

  type Method_String_Array is array (1..4) of String;
  Method_Strings : Method_String_Array := ("LSLSFSF", "LSLSFF", "LLSFSF", "LLSFF");
  Sum : Natural := 0;
  Tests : Positive := 100_000;
  PC : Float;

begin
  for I in Method_Strings'Range loop
    Sum := 0;
    for T in 1..Tests'Last loop
      Sum := Sum + Method (Method_Strings (I));
    end loop;
    PC := Float (Sum) * Float (100) / Float (Tests);
    Put (Method_Strings (I));
    Put (" produces ");
    Put (Item => PC, Fore => 2, Aft => 8, Exp => 0);
    New_Line;
  end loop;
end Two_Bullet_Roulette;

R. E. B.

  package Natural_Random is new Ada.Numerics.Discrete_Random (Natural);
  Gen : Natural_Random.Generator;

 procedure Spin (Cylinder : in out Revolver_Cylinder_Array) is
    Random_Number : Natural := Natural_Random.Random (Gen);
  begin
    for I in 1..Random_Number loop
      Rshift (Cylinder);
    end loop;
  end Spin;

I had to fix several other errors to get it to compile, but that does generate numbers as needed for me. I don’t think the result is correct and the execution time can be quite long depending on the random number chosen. Maybe constrain it to mod 128 or something to get a more suitable range.

Full diff in the linked gist:

1 Like

Wow. Just goes to show how much I need to learn about programming in general, design, flow AND syntax.

Lots to study here, but on the other hand, I was close in a lot of respects!

Thanks, for the massive help…

R. E. B

One of my favorite papers of all time is by Guy Steele et al, and is about a “splittable” random number generator, “SplitMix”. A splittable random number generator is one that can be used deterministically in a multi-threaded environment, without locks, because it can be “split” whenever a new thread is spawned that needs its own sequence of random numbers. I cannot promise you that this is relevant to your problem, but if you want to learn more about random number generators, this paper provides a great background:

If you don’t have access to the ACM digital library, you can probably just do a search for “Guy Steele” and “splittable random number generator” and find the paper or follow-ons to it. A package based on it also made it into the Java standard library, I believe.

2 Likes