| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 
 | ------------------------------------------------------------------------------
--                                                                          --
--                         GNAT RUN-TIME COMPONENTS                         --
--                                                                          --
--               G N A T . M B B S _ F L O A T _ R A N D O M                --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 1992-2010, 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.Calendar;
package body GNAT.MBBS_Float_Random is
   -------------------------
   -- Implementation Note --
   -------------------------
   --  The design of this spec is a bit awkward, as a result of Ada 95 not
   --  permitting in-out parameters for function formals (most naturally
   --  Generator values would be passed this way). In pure Ada 95, the only
   --  solution would be to add a self-referential component to the generator
   --  allowing access to the generator object from inside the function. This
   --  would work because the generator is limited, which prevents any copy.
   --  This is a bit heavy, so what we do is to use Unrestricted_Access to
   --  get a pointer to the state in the passed Generator. This works because
   --  Generator is a limited type and will thus always be passed by reference.
   package Calendar renames Ada.Calendar;
   type Pointer is access all State;
   -----------------------
   -- Local Subprograms --
   -----------------------
   procedure Euclid (P, Q : Int; X, Y : out Int; GCD : out Int);
   function  Euclid (P, Q : Int) return Int;
   function Square_Mod_N (X, N : Int) return Int;
   ------------
   -- Euclid --
   ------------
   procedure Euclid (P, Q : Int; X, Y : out Int; GCD : out Int) is
      XT : Int := 1;
      YT : Int := 0;
      procedure Recur
        (P,  Q  : Int;                    --  a (i-1), a (i)
         X,  Y  : Int;                    --  x (i),   y (i)
         XP, YP : in out Int;             --  x (i-1), y (i-1)
         GCD    : out Int);
      procedure Recur
        (P,  Q  : Int;
         X,  Y  : Int;
         XP, YP : in out Int;
         GCD    : out Int)
      is
         Quo : Int := P / Q;              --  q <-- |_ a (i-1) / a (i) _|
         XT  : Int := X;                  --  x (i)
         YT  : Int := Y;                  --  y (i)
      begin
         if P rem Q = 0 then                 --  while does not divide
            GCD := Q;
            XP  := X;
            YP  := Y;
         else
            Recur (Q, P - Q * Quo, XP - Quo * X, YP - Quo * Y, XT, YT, Quo);
            --  a (i) <== a (i)
            --  a (i+1) <-- a (i-1) - q*a (i)
            --  x (i+1) <-- x (i-1) - q*x (i)
            --  y (i+1) <-- y (i-1) - q*y (i)
            --  x (i) <== x (i)
            --  y (i) <== y (i)
            XP  := XT;
            YP  := YT;
            GCD := Quo;
         end if;
      end Recur;
   --  Start of processing for Euclid
   begin
      Recur (P, Q, 0, 1, XT, YT, GCD);
      X := XT;
      Y := YT;
   end Euclid;
   function Euclid (P, Q : Int) return Int is
      X, Y, GCD : Int;
      pragma Unreferenced (Y, GCD);
   begin
      Euclid (P, Q, X, Y, GCD);
      return X;
   end Euclid;
   -----------
   -- Image --
   -----------
   function Image (Of_State : State) return String is
   begin
      return Int'Image (Of_State.X1) & ',' & Int'Image (Of_State.X2)
             & ',' &
             Int'Image (Of_State.P)  & ',' & Int'Image (Of_State.Q);
   end Image;
   ------------
   -- Random --
   ------------
   function Random  (Gen : Generator) return Uniformly_Distributed is
      Genp : constant Pointer := Gen.Gen_State'Unrestricted_Access;
   begin
      Genp.X1 := Square_Mod_N (Genp.X1,  Genp.P);
      Genp.X2 := Square_Mod_N (Genp.X2,  Genp.Q);
      return
        Float ((Flt (((Genp.X2 - Genp.X1) * Genp.X)
                  mod Genp.Q) * Flt (Genp.P)
          + Flt (Genp.X1)) * Genp.Scl);
   end Random;
   -----------
   -- Reset --
   -----------
   --  Version that works from given initiator value
   procedure Reset (Gen : Generator; Initiator : Integer) is
      Genp   : constant Pointer := Gen.Gen_State'Unrestricted_Access;
      X1, X2 : Int;
   begin
      X1 := 2 + Int (Initiator) mod (K1 - 3);
      X2 := 2 + Int (Initiator) mod (K2 - 3);
      --  Eliminate effects of small initiators
      for J in 1 .. 5 loop
         X1 := Square_Mod_N (X1, K1);
         X2 := Square_Mod_N (X2, K2);
      end loop;
      Genp.all :=
        (X1  => X1,
         X2  => X2,
         P   => K1,
         Q   => K2,
         X   => 1,
         Scl => Scal);
   end Reset;
   --  Version that works from specific saved state
   procedure Reset (Gen : Generator; From_State : State) is
      Genp : constant Pointer := Gen.Gen_State'Unrestricted_Access;
   begin
      Genp.all := From_State;
   end Reset;
   --  Version that works from calendar
   procedure Reset (Gen : Generator) is
      Genp   : constant Pointer       := Gen.Gen_State'Unrestricted_Access;
      Now    : constant Calendar.Time := Calendar.Clock;
      X1, X2 : Int;
   begin
      X1 := Int (Calendar.Year  (Now)) * 12 * 31 +
            Int (Calendar.Month (Now)) * 31 +
            Int (Calendar.Day   (Now));
      X2 := Int (Calendar.Seconds (Now) * Duration (1000.0));
      X1 := 2 + X1 mod (K1 - 3);
      X2 := 2 + X2 mod (K2 - 3);
      --  Eliminate visible effects of same day starts
      for J in 1 .. 5 loop
         X1 := Square_Mod_N (X1, K1);
         X2 := Square_Mod_N (X2, K2);
      end loop;
      Genp.all :=
        (X1  => X1,
         X2  => X2,
         P   => K1,
         Q   => K2,
         X   => 1,
         Scl => Scal);
   end Reset;
   ----------
   -- Save --
   ----------
   procedure Save (Gen : Generator; To_State : out State) is
   begin
      To_State := Gen.Gen_State;
   end Save;
   ------------------
   -- Square_Mod_N --
   ------------------
   function Square_Mod_N (X, N : Int) return Int is
      Temp : constant Flt := Flt (X) * Flt (X);
      Div  : Int;
   begin
      Div := Int (Temp / Flt (N));
      Div := Int (Temp - Flt (Div) * Flt (N));
      if Div < 0 then
         return Div + N;
      else
         return Div;
      end if;
   end Square_Mod_N;
   -----------
   -- Value --
   -----------
   function Value (Coded_State : String) return State is
      Last  : constant Natural := Coded_State'Last;
      Start : Positive := Coded_State'First;
      Stop  : Positive := Coded_State'First;
      Outs  : State;
   begin
      while Stop <= Last and then Coded_State (Stop) /= ',' loop
         Stop := Stop + 1;
      end loop;
      if Stop > Last then
         raise Constraint_Error;
      end if;
      Outs.X1 := Int'Value (Coded_State (Start .. Stop - 1));
      Start := Stop + 1;
      loop
         Stop := Stop + 1;
         exit when Stop > Last or else Coded_State (Stop) = ',';
      end loop;
      if Stop > Last then
         raise Constraint_Error;
      end if;
      Outs.X2 := Int'Value (Coded_State (Start .. Stop - 1));
      Start := Stop + 1;
      loop
         Stop := Stop + 1;
         exit when Stop > Last or else Coded_State (Stop) = ',';
      end loop;
      if Stop > Last then
         raise Constraint_Error;
      end if;
      Outs.P   := Int'Value (Coded_State (Start .. Stop - 1));
      Outs.Q   := Int'Value (Coded_State (Stop + 1 .. Last));
      Outs.X   := Euclid (Outs.P, Outs.Q);
      Outs.Scl := 1.0 / (Flt (Outs.P) * Flt (Outs.Q));
      --  Now do *some* sanity checks
      if Outs.Q < 31 or else Outs.P < 31
        or else Outs.X1 not in 2 .. Outs.P - 1
        or else Outs.X2 not in 2 .. Outs.Q - 1
      then
         raise Constraint_Error;
      end if;
      return Outs;
   end Value;
end GNAT.MBBS_Float_Random;
 |