| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT RUN-TIME COMPONENTS -- |
| -- -- |
| -- S Y S T E M . R A N D O M _ N U M B E R S -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 2007-2022, Free Software Foundation, Inc. -- |
| -- -- |
| -- GNAT is free software; you can redistribute it and/or modify it under -- |
| -- terms of the GNU General Public License as published by the Free Soft- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- |
| -- or FITNESS FOR A PARTICULAR PURPOSE. -- |
| -- -- |
| -- As a special exception under Section 7 of GPL version 3, you are granted -- |
| -- additional permissions described in the GCC Runtime Library Exception, -- |
| -- version 3.1, as published by the Free Software Foundation. -- |
| -- -- |
| -- You should have received a copy of the GNU General Public License and -- |
| -- a copy of the GCC Runtime Library Exception along with this program; -- |
| -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- |
| -- <http://www.gnu.org/licenses/>. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| ------------------------------------------------------------------------------ |
| -- -- |
| -- The implementation here is derived from a C-program for MT19937, with -- |
| -- initialization improved 2002/1/26. As required, the following notice is -- |
| -- copied from the original program. -- |
| -- -- |
| -- Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, -- |
| -- All rights reserved. -- |
| -- -- |
| -- Redistribution and use in source and binary forms, with or without -- |
| -- modification, are permitted provided that the following conditions -- |
| -- are met: -- |
| -- -- |
| -- 1. Redistributions of source code must retain the above copyright -- |
| -- notice, this list of conditions and the following disclaimer. -- |
| -- -- |
| -- 2. Redistributions in binary form must reproduce the above copyright -- |
| -- notice, this list of conditions and the following disclaimer in the -- |
| -- documentation and/or other materials provided with the distribution.-- |
| -- -- |
| -- 3. The names of its contributors may not be used to endorse or promote -- |
| -- products derived from this software without specific prior written -- |
| -- permission. -- |
| -- -- |
| -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- |
| -- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- |
| -- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- |
| -- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- |
| -- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- |
| -- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -- |
| -- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -- |
| -- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -- |
| -- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -- |
| -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -- |
| -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| ------------------------------------------------------------------------------ |
| -- -- |
| -- This is an implementation of the Mersenne Twister, twisted generalized -- |
| -- feedback shift register of rational normal form, with state-bit -- |
| -- reflection and tempering. This version generates 32-bit integers with a -- |
| -- period of 2**19937 - 1 (a Mersenne prime, hence the name). For -- |
| -- applications requiring more than 32 bits (up to 64), we concatenate two -- |
| -- 32-bit numbers. -- |
| -- -- |
| -- See http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html for -- |
| -- details. -- |
| -- -- |
| -- In contrast to the original code, we do not generate random numbers in -- |
| -- batches of N. Measurement seems to show this has very little if any -- |
| -- effect on performance, and it may be marginally better for real-time -- |
| -- applications with hard deadlines. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Ada.Unchecked_Conversion; |
| |
| with System.Random_Seed; |
| |
| with Interfaces; use Interfaces; |
| |
| use Ada; |
| |
| package body System.Random_Numbers with |
| SPARK_Mode => Off |
| is |
| Image_Numeral_Length : constant := Max_Image_Width / N; |
| |
| subtype Image_String is String (1 .. Max_Image_Width); |
| |
| ---------------------------- |
| -- Algorithmic Parameters -- |
| ---------------------------- |
| |
| Lower_Mask : constant := 2**31 - 1; |
| Upper_Mask : constant := 2**31; |
| |
| Matrix_A : constant array (State_Val range 0 .. 1) of State_Val |
| := [0, 16#9908b0df#]; |
| -- The twist transformation is represented by a matrix of the form |
| -- |
| -- [ 0 I(31) ] |
| -- [ _a ] |
| -- |
| -- where 0 is a 31x31 block of 0s, I(31) is the 31x31 identity matrix and |
| -- _a is a particular bit row-vector, represented here by a 32-bit integer. |
| -- If integer x represents a row vector of bits (with x(0), the units bit, |
| -- last), then |
| -- x * A = [0 x(31..1)] xor Matrix_A(x(0)). |
| |
| U : constant := 11; |
| S : constant := 7; |
| B_Mask : constant := 16#9d2c5680#; |
| T : constant := 15; |
| C_Mask : constant := 16#efc60000#; |
| L : constant := 18; |
| -- The tempering shifts and bit masks, in the order applied |
| |
| Seed0 : constant := 5489; |
| -- Default seed, used to initialize the state vector when Reset not called |
| |
| Seed1 : constant := 19650218; |
| -- Seed used to initialize the state vector when calling Reset with an |
| -- initialization vector. |
| |
| Mult0 : constant := 1812433253; |
| -- Multiplier for a modified linear congruential generator used to |
| -- initialize the state vector when calling Reset with a single integer |
| -- seed. |
| |
| Mult1 : constant := 1664525; |
| Mult2 : constant := 1566083941; |
| -- Multipliers for two modified linear congruential generators used to |
| -- initialize the state vector when calling Reset with an initialization |
| -- vector. |
| |
| ----------------------- |
| -- Local Subprograms -- |
| ----------------------- |
| |
| procedure Init (Gen : Generator; Initiator : Unsigned_32); |
| -- Perform a default initialization of the state of Gen. The resulting |
| -- state is identical for identical values of Initiator. |
| |
| procedure Insert_Image |
| (S : in out Image_String; |
| Index : Integer; |
| V : State_Val); |
| -- Insert image of V into S, in the Index'th 11-character substring |
| |
| function Extract_Value (S : String; Index : Integer) return State_Val; |
| -- Treat S as a sequence of 11-character decimal numerals and return |
| -- the result of converting numeral #Index (numbering from 0) |
| |
| function To_Unsigned is |
| new Unchecked_Conversion (Integer_32, Unsigned_32); |
| function To_Unsigned is |
| new Unchecked_Conversion (Integer_64, Unsigned_64); |
| |
| ------------ |
| -- Random -- |
| ------------ |
| |
| function Random (Gen : Generator) return Unsigned_32 is |
| G : Generator renames Gen.Writable.Self.all; |
| Y : State_Val; |
| I : Integer; |
| -- Naming exception: I is fine to use here as it is the name used in |
| -- the original paper describing the Mersenne Twister and in common |
| -- descriptions of the algorithm. |
| |
| begin |
| I := G.I; |
| |
| if I < N - M then |
| Y := (G.S (I) and Upper_Mask) or (G.S (I + 1) and Lower_Mask); |
| Y := G.S (I + M) xor Shift_Right (Y, 1) xor Matrix_A (Y and 1); |
| I := I + 1; |
| |
| elsif I < N - 1 then |
| Y := (G.S (I) and Upper_Mask) or (G.S (I + 1) and Lower_Mask); |
| Y := G.S (I + (M - N)) |
| xor Shift_Right (Y, 1) |
| xor Matrix_A (Y and 1); |
| I := I + 1; |
| |
| elsif I = N - 1 then |
| Y := (G.S (I) and Upper_Mask) or (G.S (0) and Lower_Mask); |
| Y := G.S (M - 1) xor Shift_Right (Y, 1) xor Matrix_A (Y and 1); |
| I := 0; |
| |
| else |
| Init (G, Seed0); |
| return Random (Gen); |
| end if; |
| |
| G.S (G.I) := Y; |
| G.I := I; |
| |
| Y := Y xor Shift_Right (Y, U); |
| Y := Y xor (Shift_Left (Y, S) and B_Mask); |
| Y := Y xor (Shift_Left (Y, T) and C_Mask); |
| Y := Y xor Shift_Right (Y, L); |
| |
| return Y; |
| end Random; |
| |
| generic |
| type Unsigned is mod <>; |
| type Real is digits <>; |
| with function Random (G : Generator) return Unsigned is <>; |
| function Random_Float_Template (Gen : Generator) return Real; |
| pragma Inline (Random_Float_Template); |
| -- Template for a random-number generator implementation that delivers |
| -- values of type Real in the range [0 .. 1], using values from Gen, |
| -- assuming that Unsigned is large enough to hold the bits of a mantissa |
| -- for type Real. |
| |
| --------------------------- |
| -- Random_Float_Template -- |
| --------------------------- |
| |
| function Random_Float_Template (Gen : Generator) return Real is |
| |
| pragma Compile_Time_Error |
| (Unsigned'Last <= 2**(Real'Machine_Mantissa - 1), |
| "insufficiently large modular type used to hold mantissa"); |
| |
| begin |
| -- This code generates random floating-point numbers from unsigned |
| -- integers. Assuming that Real'Machine_Radix = 2, it can deliver all |
| -- machine values of type Real (as implied by Real'Machine_Mantissa and |
| -- Real'Machine_Emin), which is not true of the standard method (to |
| -- which we fall back for nonbinary radix): computing Real(<random |
| -- integer>) / (<max random integer>+1). To do so, we first extract an |
| -- (M-1)-bit significand (where M is Real'Machine_Mantissa), and then |
| -- decide on a normalized exponent by repeated coin flips, decrementing |
| -- from 0 as long as we flip heads (1 bits). This process yields the |
| -- proper geometric distribution for the exponent: in a uniformly |
| -- distributed set of floating-point numbers, 1/2 of them will be in |
| -- (0.5, 1], 1/4 will be in (0.25, 0.5], and so forth. It makes a |
| -- further adjustment at binade boundaries (see comments below) to give |
| -- the effect of selecting a uniformly distributed real deviate in |
| -- [0..1] and then rounding to the nearest representable floating-point |
| -- number. The algorithm attempts to be stingy with random integers. In |
| -- the worst case, it can consume roughly -Real'Machine_Emin/32 32-bit |
| -- integers, but this case occurs with probability around |
| -- 2**Machine_Emin, and the expected number of calls to integer-valued |
| -- Random is 1. For another discussion of the issues addressed by this |
| -- process, see Allen Downey's unpublished paper at |
| -- http://allendowney.com/research/rand/downey07randfloat.pdf. |
| |
| if Real'Machine_Radix /= 2 then |
| return Real'Machine |
| (Real (Unsigned'(Random (Gen))) * 2.0**(-Unsigned'Size)); |
| |
| else |
| declare |
| type Bit_Count is range 0 .. 4; |
| |
| subtype T is Real'Base; |
| |
| Trailing_Ones : constant array (Unsigned_32 range 0 .. 15) |
| of Bit_Count := |
| [2#00000# => 0, 2#00001# => 1, 2#00010# => 0, 2#00011# => 2, |
| 2#00100# => 0, 2#00101# => 1, 2#00110# => 0, 2#00111# => 3, |
| 2#01000# => 0, 2#01001# => 1, 2#01010# => 0, 2#01011# => 2, |
| 2#01100# => 0, 2#01101# => 1, 2#01110# => 0, 2#01111# => 4]; |
| |
| Pow_Tab : constant array (Bit_Count range 0 .. 3) of Real |
| := [0 => 2.0**(0 - T'Machine_Mantissa), |
| 1 => 2.0**(-1 - T'Machine_Mantissa), |
| 2 => 2.0**(-2 - T'Machine_Mantissa), |
| 3 => 2.0**(-3 - T'Machine_Mantissa)]; |
| |
| Extra_Bits : constant Natural := |
| (Unsigned'Size - T'Machine_Mantissa + 1); |
| -- Random bits left over after selecting mantissa |
| |
| Mantissa : Unsigned; |
| |
| X : Real; -- Scaled mantissa |
| R : Unsigned_32; -- Supply of random bits |
| R_Bits : Natural; -- Number of bits left in R |
| K : Bit_Count; -- Next decrement to exponent |
| |
| begin |
| K := 0; |
| Mantissa := Random (Gen) / 2**Extra_Bits; |
| R := Unsigned_32 (Mantissa mod 2**Extra_Bits); |
| R_Bits := Extra_Bits; |
| X := Real (2**(T'Machine_Mantissa - 1) + Mantissa); -- Exact |
| |
| if Extra_Bits < 4 and then R < 2 ** Extra_Bits - 1 then |
| |
| -- We got lucky and got a zero in our few extra bits |
| |
| K := Trailing_Ones (R); |
| |
| else |
| Find_Zero : loop |
| |
| -- R has R_Bits unprocessed random bits, a multiple of 4. |
| -- X needs to be halved for each trailing one bit. The |
| -- process stops as soon as a 0 bit is found. If R_Bits |
| -- becomes zero, reload R. |
| |
| -- Process 4 bits at a time for speed: the two iterations |
| -- on average with three tests each was still too slow, |
| -- probably because the branches are not predictable. |
| -- This loop now will only execute once 94% of the cases, |
| -- doing more bits at a time will not help. |
| |
| while R_Bits >= 4 loop |
| K := Trailing_Ones (R mod 16); |
| |
| exit Find_Zero when K < 4; -- Exits 94% of the time |
| |
| R_Bits := R_Bits - 4; |
| X := X / 16.0; |
| R := R / 16; |
| end loop; |
| |
| -- Do not allow us to loop endlessly even in the (very |
| -- unlikely) case that Random (Gen) keeps yielding all ones. |
| |
| exit Find_Zero when X = 0.0; |
| R := Random (Gen); |
| R_Bits := 32; |
| end loop Find_Zero; |
| end if; |
| |
| -- K has the count of trailing ones not reflected yet in X. The |
| -- following multiplication takes care of that, as well as the |
| -- correction to move the radix point to the left of the mantissa. |
| -- Doing it at the end avoids repeated rounding errors in the |
| -- exceedingly unlikely case of ever having a subnormal result. |
| |
| X := X * Pow_Tab (K); |
| |
| -- The smallest value in each binade is rounded to by 0.75 of |
| -- the span of real numbers as its next larger neighbor, and |
| -- 1.0 is rounded to by half of the span of real numbers as its |
| -- next smaller neighbor. To account for this, when we encounter |
| -- the smallest number in a binade, we substitute the smallest |
| -- value in the next larger binade with probability 1/2. |
| |
| if Mantissa = 0 and then Unsigned_32'(Random (Gen)) mod 2 = 0 then |
| X := 2.0 * X; |
| end if; |
| |
| return X; |
| end; |
| end if; |
| end Random_Float_Template; |
| |
| ------------ |
| -- Random -- |
| ------------ |
| |
| function Random (Gen : Generator) return Float is |
| function F is new Random_Float_Template (Unsigned_32, Float); |
| begin |
| return F (Gen); |
| end Random; |
| |
| function Random (Gen : Generator) return Long_Float is |
| function F is new Random_Float_Template (Unsigned_64, Long_Float); |
| begin |
| return F (Gen); |
| end Random; |
| |
| function Random (Gen : Generator) return Unsigned_64 is |
| begin |
| return Shift_Left (Unsigned_64 (Unsigned_32'(Random (Gen))), 32) |
| or Unsigned_64 (Unsigned_32'(Random (Gen))); |
| end Random; |
| |
| function Random (Gen : Generator) return Unsigned_128 is |
| begin |
| return Shift_Left (Unsigned_128 (Unsigned_64'(Random (Gen))), 64) |
| or Unsigned_128 (Unsigned_64'(Random (Gen))); |
| end Random; |
| |
| --------------------- |
| -- Random_Discrete -- |
| --------------------- |
| |
| function Random_Discrete |
| (Gen : Generator; |
| Min : Result_Subtype := Default_Min; |
| Max : Result_Subtype := Result_Subtype'Last) return Result_Subtype |
| is |
| begin |
| if Max = Min then |
| return Max; |
| |
| elsif Max < Min then |
| raise Constraint_Error; |
| |
| -- In the 128-bit case, we have to be careful since not all 128-bit |
| -- unsigned values are representable in GNAT's universal integer. |
| |
| elsif Result_Subtype'Base'Size > 64 then |
| declare |
| -- Ignore unequal-size warnings since GNAT's handling is correct. |
| |
| pragma Warnings ("Z"); |
| function Conv_To_Unsigned is |
| new Unchecked_Conversion (Result_Subtype'Base, Unsigned_128); |
| function Conv_To_Result is |
| new Unchecked_Conversion (Unsigned_128, Result_Subtype'Base); |
| pragma Warnings ("z"); |
| |
| N : constant Unsigned_128 := |
| Conv_To_Unsigned (Max) - Conv_To_Unsigned (Min) + 1; |
| |
| X, Slop : Unsigned_128; |
| |
| begin |
| if N = 0 then |
| return Conv_To_Result (Conv_To_Unsigned (Min) + Random (Gen)); |
| |
| else |
| Slop := Unsigned_128'Last rem N + 1; |
| |
| loop |
| X := Random (Gen); |
| exit when Slop = N or else X <= Unsigned_128'Last - Slop; |
| end loop; |
| |
| return Conv_To_Result (Conv_To_Unsigned (Min) + X rem N); |
| end if; |
| end; |
| |
| -- In the 64-bit case, we have to be careful since not all 64-bit |
| -- unsigned values are representable in GNAT's universal integer. |
| |
| elsif Result_Subtype'Base'Size > 32 then |
| declare |
| -- Ignore unequal-size warnings since GNAT's handling is correct. |
| |
| pragma Warnings ("Z"); |
| function Conv_To_Unsigned is |
| new Unchecked_Conversion (Result_Subtype'Base, Unsigned_64); |
| function Conv_To_Result is |
| new Unchecked_Conversion (Unsigned_64, Result_Subtype'Base); |
| pragma Warnings ("z"); |
| |
| N : constant Unsigned_64 := |
| Conv_To_Unsigned (Max) - Conv_To_Unsigned (Min) + 1; |
| |
| X, Slop : Unsigned_64; |
| |
| begin |
| if N = 0 then |
| return Conv_To_Result (Conv_To_Unsigned (Min) + Random (Gen)); |
| |
| else |
| Slop := Unsigned_64'Last rem N + 1; |
| |
| loop |
| X := Random (Gen); |
| exit when Slop = N or else X <= Unsigned_64'Last - Slop; |
| end loop; |
| |
| return Conv_To_Result (Conv_To_Unsigned (Min) + X rem N); |
| end if; |
| end; |
| |
| -- In the 32-bit case, we need to handle both integer and enumeration |
| -- types and, therefore, rely on 'Pos and 'Val in the computation. |
| |
| elsif Result_Subtype'Pos (Max) - Result_Subtype'Pos (Min) = 2 ** 32 - 1 |
| then |
| return Result_Subtype'Val |
| (Result_Subtype'Pos (Min) + Unsigned_32'Pos (Random (Gen))); |
| |
| else |
| declare |
| N : constant Unsigned_32 := |
| Unsigned_32 (Result_Subtype'Pos (Max) - |
| Result_Subtype'Pos (Min) + 1); |
| Slop : constant Unsigned_32 := Unsigned_32'Last rem N + 1; |
| X : Unsigned_32; |
| |
| begin |
| loop |
| X := Random (Gen); |
| exit when Slop = N or else X <= Unsigned_32'Last - Slop; |
| end loop; |
| |
| return |
| Result_Subtype'Val |
| (Result_Subtype'Pos (Min) + Unsigned_32'Pos (X rem N)); |
| end; |
| end if; |
| end Random_Discrete; |
| |
| ------------------ |
| -- Random_Float -- |
| ------------------ |
| |
| function Random_Float (Gen : Generator) return Result_Subtype is |
| begin |
| if Result_Subtype'Base'Digits > Float'Digits then |
| return Result_Subtype'Machine (Result_Subtype |
| (Long_Float'(Random (Gen)))); |
| else |
| return Result_Subtype'Machine (Result_Subtype |
| (Float'(Random (Gen)))); |
| end if; |
| end Random_Float; |
| |
| ----------- |
| -- Reset -- |
| ----------- |
| |
| procedure Reset (Gen : Generator) is |
| begin |
| Init (Gen, Unsigned_32'Mod (Random_Seed.Get_Seed)); |
| end Reset; |
| |
| procedure Reset (Gen : Generator; Initiator : Integer_32) is |
| begin |
| Init (Gen, To_Unsigned (Initiator)); |
| end Reset; |
| |
| procedure Reset (Gen : Generator; Initiator : Unsigned_32) is |
| begin |
| Init (Gen, Initiator); |
| end Reset; |
| |
| procedure Reset (Gen : Generator; Initiator : Integer) is |
| begin |
| -- This is probably an unnecessary precaution against future change, but |
| -- since the test is a static expression, no extra code is involved. |
| |
| if Integer'Size <= 32 then |
| Init (Gen, To_Unsigned (Integer_32 (Initiator))); |
| |
| else |
| declare |
| Initiator1 : constant Unsigned_64 := |
| To_Unsigned (Integer_64 (Initiator)); |
| Init0 : constant Unsigned_32 := |
| Unsigned_32 (Initiator1 mod 2 ** 32); |
| Init1 : constant Unsigned_32 := |
| Unsigned_32 (Shift_Right (Initiator1, 32)); |
| begin |
| Reset (Gen, Initialization_Vector'(Init0, Init1)); |
| end; |
| end if; |
| end Reset; |
| |
| procedure Reset (Gen : Generator; Initiator : Initialization_Vector) is |
| G : Generator renames Gen.Writable.Self.all; |
| I, J : Integer; |
| |
| begin |
| Init (G, Seed1); |
| I := 1; |
| J := 0; |
| |
| if Initiator'Length > 0 then |
| for K in reverse 1 .. Integer'Max (N, Initiator'Length) loop |
| G.S (I) := |
| (G.S (I) xor ((G.S (I - 1) |
| xor Shift_Right (G.S (I - 1), 30)) * Mult1)) |
| + Initiator (J + Initiator'First) + Unsigned_32 (J); |
| |
| I := I + 1; |
| J := J + 1; |
| |
| if I >= N then |
| G.S (0) := G.S (N - 1); |
| I := 1; |
| end if; |
| |
| if J >= Initiator'Length then |
| J := 0; |
| end if; |
| end loop; |
| end if; |
| |
| for K in reverse 1 .. N - 1 loop |
| G.S (I) := |
| (G.S (I) xor ((G.S (I - 1) |
| xor Shift_Right (G.S (I - 1), 30)) * Mult2)) |
| - Unsigned_32 (I); |
| I := I + 1; |
| |
| if I >= N then |
| G.S (0) := G.S (N - 1); |
| I := 1; |
| end if; |
| end loop; |
| |
| G.S (0) := Upper_Mask; |
| end Reset; |
| |
| procedure Reset (Gen : Generator; From_State : Generator) is |
| G : Generator renames Gen.Writable.Self.all; |
| begin |
| G.S := From_State.S; |
| G.I := From_State.I; |
| end Reset; |
| |
| procedure Reset (Gen : Generator; From_State : State) is |
| G : Generator renames Gen.Writable.Self.all; |
| begin |
| G.I := 0; |
| G.S := From_State; |
| end Reset; |
| |
| procedure Reset (Gen : Generator; From_Image : String) is |
| G : Generator renames Gen.Writable.Self.all; |
| begin |
| G.I := 0; |
| |
| for J in 0 .. N - 1 loop |
| G.S (J) := Extract_Value (From_Image, J); |
| end loop; |
| end Reset; |
| |
| ---------- |
| -- Save -- |
| ---------- |
| |
| procedure Save (Gen : Generator; To_State : out State) is |
| Gen2 : Generator; |
| |
| begin |
| if Gen.I = N then |
| Init (Gen2, 5489); |
| To_State := Gen2.S; |
| |
| else |
| To_State (0 .. N - 1 - Gen.I) := Gen.S (Gen.I .. N - 1); |
| To_State (N - Gen.I .. N - 1) := Gen.S (0 .. Gen.I - 1); |
| end if; |
| end Save; |
| |
| ----------- |
| -- Image -- |
| ----------- |
| |
| function Image (Of_State : State) return String is |
| Result : Image_String; |
| |
| begin |
| Result := [others => ' ']; |
| |
| for J in Of_State'Range loop |
| Insert_Image (Result, J, Of_State (J)); |
| end loop; |
| |
| return Result; |
| end Image; |
| |
| function Image (Gen : Generator) return String is |
| Result : Image_String; |
| |
| begin |
| Result := [others => ' ']; |
| for J in 0 .. N - 1 loop |
| Insert_Image (Result, J, Gen.S ((J + Gen.I) mod N)); |
| end loop; |
| |
| return Result; |
| end Image; |
| |
| --------------- |
| -- Put_Image -- |
| --------------- |
| |
| procedure Put_Image |
| (S : in out Strings.Text_Buffers.Root_Buffer_Type'Class; V : State) is |
| begin |
| Strings.Text_Buffers.Put (S, Image (V)); |
| end Put_Image; |
| |
| ----------- |
| -- Value -- |
| ----------- |
| |
| function Value (Coded_State : String) return State is |
| Gen : Generator; |
| S : State; |
| begin |
| Reset (Gen, Coded_State); |
| Save (Gen, S); |
| return S; |
| end Value; |
| |
| ---------- |
| -- Init -- |
| ---------- |
| |
| procedure Init (Gen : Generator; Initiator : Unsigned_32) is |
| G : Generator renames Gen.Writable.Self.all; |
| begin |
| G.S (0) := Initiator; |
| |
| for I in 1 .. N - 1 loop |
| G.S (I) := |
| (G.S (I - 1) xor Shift_Right (G.S (I - 1), 30)) * Mult0 |
| + Unsigned_32 (I); |
| end loop; |
| |
| G.I := 0; |
| end Init; |
| |
| ------------------ |
| -- Insert_Image -- |
| ------------------ |
| |
| procedure Insert_Image |
| (S : in out Image_String; |
| Index : Integer; |
| V : State_Val) |
| is |
| Value : constant String := State_Val'Image (V); |
| begin |
| S (Index * 11 + 1 .. Index * 11 + Value'Length) := Value; |
| end Insert_Image; |
| |
| ------------------- |
| -- Extract_Value -- |
| ------------------- |
| |
| function Extract_Value (S : String; Index : Integer) return State_Val is |
| Start : constant Integer := S'First + Index * Image_Numeral_Length; |
| begin |
| return State_Val'Value (S (Start .. Start + Image_Numeral_Length - 1)); |
| end Extract_Value; |
| |
| end System.Random_Numbers; |