packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/andrea-m2/lib/eth-hamburg/randomly.mod

IMPLEMENTATION MODULE Randomly;

(* procedures for getting random numbers *)

(* J. Andrea, Jun.2/92 - add NormalRandom *)
(* J. Andrea, Oct.4/91, add min and max to RandomReal *)
(* reorganized, J. Andrea, Aug.12/91 *)
(* J. Andrea, 1985 *)
(* This code may be freely used and distributed, it may not be sold. *)

FROM DateTime IMPORT TimeType, Time, ConvertTime;
FROM MathLib0 IMPORT random, sqrt;

VAR
  seed :INTEGER;


    (* --------------------------------------------- *)
    PROCEDURE RandomReal( min, max :REAL ) :REAL;
    (* return a real number X, such that min >= X < max *)

    BEGIN

       RETURN min + ( max - min ) * random( seed );

    END RandomReal;

    (* --------------------------------------------- *)
    PROCEDURE NormalRandom( mean, sigma :REAL ) :REAL;
    (* from CACM Aug.63, algorithm #200 *)
    CONST
       n = 13;
    VAR
       i   :CARDINAL;
       sum :REAL;
    BEGIN

       sum := 0.0;
       FOR i := 1 TO n DO
         sum := sum + RandomReal( -1.0, +1.0 );
       END;
       RETURN mean + sigma * sum * sqrt( 3.0 / FLOAT( n ) );

    END NormalRandom;

    (* --------------------------------------------- *)
    PROCEDURE Choose_0_To_N( n :CARDINAL) :CARDINAL;
    (* return a value in the range  [0..n] *)

    BEGIN

       RETURN TRUNC( random(seed) * FLOAT(n+1) );

    END Choose_0_To_N;

    (* --------------------------------------------- *)
    PROCEDURE Choose_0_To_N_Minus_1( n :CARDINAL) :CARDINAL;
    (* return a value in the range  [0..n-1] *)

    BEGIN

       IF n < 2 THEN
         RETURN 0;
       ELSE

         RETURN TRUNC( random(seed) * FLOAT(n) );

       END;

    END Choose_0_To_N_Minus_1;


    (* --------------------------------------------- *)
    PROCEDURE Choose_1_To_N( n :CARDINAL) :CARDINAL;
    (* return a value in the range  [1..n] *)

    BEGIN

       IF n < 2 THEN
         RETURN 1;
       ELSE

         RETURN TRUNC( random(seed) * FLOAT(n) ) + 1;

       END;

    END Choose_1_To_N;


    (* --------------------------------------------- *)
    PROCEDURE Choose_1_To_N_Minus_1( n :CARDINAL) :CARDINAL;
    (* return a value in the range  [1..n-1] *)

    BEGIN

       IF n < 2 THEN
         RETURN 1;
       ELSE

         RETURN TRUNC( random(seed) * FLOAT(n-1) ) + 1;

       END;

    END Choose_1_To_N_Minus_1;


    (* --------------------------------------------- *)
    PROCEDURE InputSeed( a_seed :INTEGER );
    (* build a seed from a value from the input value *)

    VAR
      x :REAL;
    BEGIN

      (* make sure the seed is a positive large odd integer *)
      seed := ABS(a_seed);
      IF seed = 0 THEN
         seed := 654321;
      END; (* if *)

      WHILE seed < 1000000 DO
         seed := seed * 11;
      END; (* while *)
      IF NOT ODD(seed) THEN
         seed := seed + 1;
      END; (* if *)

      (* call random a couple of times to get the seed going *)
      x := random( seed );
      x := random( seed );
      x := random( seed );
      
    END InputSeed;

    (* --------------------------------------------- *)
    PROCEDURE MakeSeed;
    (* build a seed from time of day *)

    VAR
      time_string          :ARRAY [0..80] OF CHAR;
      now                  :TimeType;
      seconds , i , factor :CARDINAL;
      seed                 :INTEGER;

    BEGIN

      Time( now );     ConvertTime( now, time_string );

      seconds := 0;
      factor  := 3600;

      FOR i := 12 TO 18 BY 3 DO
         seconds := seconds + factor * 10 * ( ORD( time_string[i]   ) - 48 );
         seconds := seconds + factor *      ( ORD( time_string[i+1] ) - 48 );
         factor  := factor DIV 60;
      END; (* for *)

      (* give it the number of seconds since midnight *)
      seed := INTEGER( seconds);

      InputSeed( seed ); 

    END MakeSeed;

BEGIN

   MakeSeed;

END Randomly.