| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT RUN-TIME COMPONENTS -- |
| -- -- |
| -- G N A T . 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. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Ada.Numerics.Long_Elementary_Functions; |
| use Ada.Numerics.Long_Elementary_Functions; |
| with Ada.Unchecked_Conversion; |
| |
| with System.Random_Numbers; use System.Random_Numbers; |
| |
| package body GNAT.Random_Numbers with |
| SPARK_Mode => Off |
| is |
| Sys_Max_Image_Width : constant := System.Random_Numbers.Max_Image_Width; |
| |
| subtype Image_String is String (1 .. Max_Image_Width); |
| |
| -- Utility function declarations |
| |
| procedure Insert_Image |
| (S : in out Image_String; |
| Index : Integer; |
| V : Integer_64); |
| -- Insert string representation of V in S starting at position Index |
| |
| --------------- |
| -- To_Signed -- |
| --------------- |
| |
| function To_Signed is |
| new Ada.Unchecked_Conversion (Unsigned_32, Integer_32); |
| function To_Signed is |
| new Ada.Unchecked_Conversion (Unsigned_64, Integer_64); |
| function To_Signed is |
| new Ada.Unchecked_Conversion (Unsigned_128, Integer_128); |
| |
| ------------------ |
| -- Insert_Image -- |
| ------------------ |
| |
| procedure Insert_Image |
| (S : in out Image_String; |
| Index : Integer; |
| V : Integer_64) |
| is |
| Image : constant String := Integer_64'Image (V); |
| begin |
| S (Index .. Index + Image'Length - 1) := Image; |
| end Insert_Image; |
| |
| --------------------- |
| -- Random_Discrete -- |
| --------------------- |
| |
| function Random_Discrete |
| (Gen : Generator; |
| Min : Result_Subtype := Default_Min; |
| Max : Result_Subtype := Result_Subtype'Last) return Result_Subtype |
| is |
| function F is |
| new System.Random_Numbers.Random_Discrete |
| (Result_Subtype, Default_Min); |
| begin |
| return F (Gen.Rep, Min, Max); |
| end Random_Discrete; |
| |
| -------------------------- |
| -- Random_Decimal_Fixed -- |
| -------------------------- |
| |
| function Random_Decimal_Fixed |
| (Gen : Generator; |
| Min : Result_Subtype := Default_Min; |
| Max : Result_Subtype := Result_Subtype'Last) return Result_Subtype |
| is |
| begin |
| if Result_Subtype'Base'Size > 64 then |
| declare |
| subtype IntV is Integer_128 range |
| Integer_128'Integer_Value (Min) .. |
| Integer_128'Integer_Value (Max); |
| function R is new Random_Discrete (Integer_128, IntV'First); |
| begin |
| return Result_Subtype'Fixed_Value (R (Gen, IntV'First, IntV'Last)); |
| end; |
| |
| elsif Result_Subtype'Base'Size > 32 then |
| declare |
| subtype IntV is Integer_64 range |
| Integer_64'Integer_Value (Min) .. |
| Integer_64'Integer_Value (Max); |
| function R is new Random_Discrete (Integer_64, IntV'First); |
| begin |
| return Result_Subtype'Fixed_Value (R (Gen, IntV'First, IntV'Last)); |
| end; |
| |
| else |
| declare |
| subtype IntV is Integer_32 range |
| Integer_32'Integer_Value (Min) .. |
| Integer_32'Integer_Value (Max); |
| function R is new Random_Discrete (Integer_32, IntV'First); |
| begin |
| return Result_Subtype'Fixed_Value (R (Gen, IntV'First, IntV'Last)); |
| end; |
| end if; |
| end Random_Decimal_Fixed; |
| |
| --------------------------- |
| -- Random_Ordinary_Fixed -- |
| --------------------------- |
| |
| function Random_Ordinary_Fixed |
| (Gen : Generator; |
| Min : Result_Subtype := Default_Min; |
| Max : Result_Subtype := Result_Subtype'Last) return Result_Subtype |
| is |
| begin |
| if Result_Subtype'Base'Size > 64 then |
| declare |
| subtype IntV is Integer_128 range |
| Integer_128'Integer_Value (Min) .. |
| Integer_128'Integer_Value (Max); |
| function R is new Random_Discrete (Integer_128, IntV'First); |
| begin |
| return Result_Subtype'Fixed_Value (R (Gen, IntV'First, IntV'Last)); |
| end; |
| |
| elsif Result_Subtype'Base'Size > 32 then |
| declare |
| subtype IntV is Integer_64 range |
| Integer_64'Integer_Value (Min) .. |
| Integer_64'Integer_Value (Max); |
| function R is new Random_Discrete (Integer_64, IntV'First); |
| begin |
| return Result_Subtype'Fixed_Value (R (Gen, IntV'First, IntV'Last)); |
| end; |
| |
| else |
| declare |
| subtype IntV is Integer_32 range |
| Integer_32'Integer_Value (Min) .. |
| Integer_32'Integer_Value (Max); |
| function R is new Random_Discrete (Integer_32, IntV'First); |
| begin |
| return Result_Subtype'Fixed_Value (R (Gen, IntV'First, IntV'Last)); |
| end; |
| end if; |
| end Random_Ordinary_Fixed; |
| |
| ------------ |
| -- Random -- |
| ------------ |
| |
| function Random (Gen : Generator) return Float is |
| begin |
| return Random (Gen.Rep); |
| end Random; |
| |
| function Random (Gen : Generator) return Long_Float is |
| begin |
| return Random (Gen.Rep); |
| end Random; |
| |
| function Random (Gen : Generator) return Interfaces.Unsigned_32 is |
| begin |
| return Random (Gen.Rep); |
| end Random; |
| |
| function Random (Gen : Generator) return Interfaces.Unsigned_64 is |
| begin |
| return Random (Gen.Rep); |
| end Random; |
| |
| function Random (Gen : Generator) return Interfaces.Unsigned_128 is |
| begin |
| return Random (Gen.Rep); |
| end Random; |
| |
| function Random (Gen : Generator) return Integer_32 is |
| begin |
| return To_Signed (Unsigned_32'(Random (Gen))); |
| end Random; |
| |
| function Random (Gen : Generator) return Integer_64 is |
| begin |
| return To_Signed (Unsigned_64'(Random (Gen))); |
| end Random; |
| |
| function Random (Gen : Generator) return Integer_128 is |
| begin |
| return To_Signed (Unsigned_128'(Random (Gen))); |
| end Random; |
| |
| function Random (Gen : Generator) return Long_Integer is |
| function Random_Long_Integer is new Random_Discrete (Long_Integer); |
| begin |
| return Random_Long_Integer (Gen); |
| end Random; |
| |
| function Random (Gen : Generator) return Integer is |
| function Random_Integer is new Random_Discrete (Integer); |
| begin |
| return Random_Integer (Gen); |
| end Random; |
| |
| ------------------ |
| -- Random_Float -- |
| ------------------ |
| |
| function Random_Float (Gen : Generator) return Result_Subtype is |
| function F is new System.Random_Numbers.Random_Float (Result_Subtype); |
| begin |
| return F (Gen.Rep); |
| end Random_Float; |
| |
| --------------------- |
| -- Random_Gaussian -- |
| --------------------- |
| |
| -- Generates pairs of normally distributed values using the polar method of |
| -- G. E. P. Box, M. E. Muller, and G. Marsaglia. See Donald E. Knuth, The |
| -- Art of Computer Programming, Vol 2: Seminumerical Algorithms, section |
| -- 3.4.1, subsection C, algorithm P. Returns half of the pair on each call, |
| -- using the Next_Gaussian field of Gen to hold the second member on |
| -- even-numbered calls. |
| |
| function Random_Gaussian (Gen : Generator) return Long_Float is |
| G : Generator renames Gen'Unrestricted_Access.all; |
| |
| V1, V2, Rad2, Mult : Long_Float; |
| |
| begin |
| if G.Have_Gaussian then |
| G.Have_Gaussian := False; |
| return G.Next_Gaussian; |
| |
| else |
| loop |
| V1 := 2.0 * Random (G) - 1.0; |
| V2 := 2.0 * Random (G) - 1.0; |
| Rad2 := V1 ** 2 + V2 ** 2; |
| exit when Rad2 < 1.0 and then Rad2 /= 0.0; |
| end loop; |
| |
| -- Now V1 and V2 are coordinates in the unit circle |
| |
| Mult := Sqrt (-2.0 * Log (Rad2) / Rad2); |
| G.Next_Gaussian := V2 * Mult; |
| G.Have_Gaussian := True; |
| return Long_Float'Machine (V1 * Mult); |
| end if; |
| end Random_Gaussian; |
| |
| function Random_Gaussian (Gen : Generator) return Float is |
| V : constant Long_Float := Random_Gaussian (Gen); |
| begin |
| return Float'Machine (Float (V)); |
| end Random_Gaussian; |
| |
| ----------- |
| -- Reset -- |
| ----------- |
| |
| procedure Reset (Gen : out Generator) is |
| begin |
| Reset (Gen.Rep); |
| Gen.Have_Gaussian := False; |
| end Reset; |
| |
| procedure Reset |
| (Gen : out Generator; |
| Initiator : Initialization_Vector) |
| is |
| begin |
| Reset (Gen.Rep, Initiator); |
| Gen.Have_Gaussian := False; |
| end Reset; |
| |
| procedure Reset |
| (Gen : out Generator; |
| Initiator : Interfaces.Integer_32) |
| is |
| begin |
| Reset (Gen.Rep, Initiator); |
| Gen.Have_Gaussian := False; |
| end Reset; |
| |
| procedure Reset |
| (Gen : out Generator; |
| Initiator : Interfaces.Unsigned_32) |
| is |
| begin |
| Reset (Gen.Rep, Initiator); |
| Gen.Have_Gaussian := False; |
| end Reset; |
| |
| procedure Reset |
| (Gen : out Generator; |
| Initiator : Integer) |
| is |
| begin |
| Reset (Gen.Rep, Initiator); |
| Gen.Have_Gaussian := False; |
| end Reset; |
| |
| procedure Reset |
| (Gen : out Generator; |
| From_State : Generator) |
| is |
| begin |
| Reset (Gen.Rep, From_State.Rep); |
| Gen.Have_Gaussian := From_State.Have_Gaussian; |
| Gen.Next_Gaussian := From_State.Next_Gaussian; |
| end Reset; |
| |
| Frac_Scale : constant Long_Float := |
| Long_Float |
| (Long_Float'Machine_Radix) ** Long_Float'Machine_Mantissa; |
| |
| function Val64 (Image : String) return Integer_64; |
| -- Renames Integer64'Value |
| -- We cannot use a 'renames Integer64'Value' since for some strange |
| -- reason, this requires a dependency on s-auxdec.ads which not all |
| -- run-times support ??? |
| |
| function Val64 (Image : String) return Integer_64 is |
| begin |
| return Integer_64'Value (Image); |
| end Val64; |
| |
| procedure Reset |
| (Gen : out Generator; |
| From_Image : String) |
| is |
| F0 : constant Integer := From_Image'First; |
| T0 : constant Integer := From_Image'First + Sys_Max_Image_Width; |
| |
| begin |
| Reset (Gen.Rep, From_Image (F0 .. F0 + Sys_Max_Image_Width)); |
| |
| if From_Image (T0 + 1) = '1' then |
| Gen.Have_Gaussian := True; |
| Gen.Next_Gaussian := |
| Long_Float (Val64 (From_Image (T0 + 3 .. T0 + 23))) / Frac_Scale |
| * Long_Float (Long_Float'Machine_Radix) |
| ** Integer (Val64 (From_Image (T0 + 25 .. From_Image'Last))); |
| else |
| Gen.Have_Gaussian := False; |
| end if; |
| end Reset; |
| |
| ----------- |
| -- Image -- |
| ----------- |
| |
| function Image (Gen : Generator) return String is |
| Result : Image_String; |
| |
| begin |
| Result := [others => ' ']; |
| Result (1 .. Sys_Max_Image_Width) := Image (Gen.Rep); |
| |
| if Gen.Have_Gaussian then |
| Result (Sys_Max_Image_Width + 2) := '1'; |
| Insert_Image (Result, Sys_Max_Image_Width + 4, |
| Integer_64 (Long_Float'Fraction (Gen.Next_Gaussian) |
| * Frac_Scale)); |
| Insert_Image (Result, Sys_Max_Image_Width + 24, |
| Integer_64 (Long_Float'Exponent (Gen.Next_Gaussian))); |
| |
| else |
| Result (Sys_Max_Image_Width + 2) := '0'; |
| end if; |
| |
| return Result; |
| end Image; |
| |
| end GNAT.Random_Numbers; |