# Funktionen für Zufallszahlen

# Zufallszahlengenerator nach [Knuth: The Art of Computer Programming, Vol. II,
# Seminumerical Algorithms, 3.3.4., Table 1, Line 30], nach C. Haynes:
# X eine 64-Bit-Zahl. Iteration X := (a*X+c) mod m
# mit m=2^64, a=6364136223846793005, c=1.

# random_L(randomstate) liefert eine neue Zufallszahl.
# > randomstate: ein Random-State, wird verändert
# < ergebnis: eine 32-Bit-Zufallszahl
  local uint32 random_L (object randomstate);
  local uint32 random_L(randomstate)
    var object randomstate;
    { var object seed = # letzte Zahl, ein Simple-Bit-Vektor mit 64 Bits
        The_Random_state(randomstate)->random_state_seed;
      var uintD* seedMSDptr = (uintD*)(&TheSbvector(seed)->data[0]);
      # Multiplikator a=6364136223846793005 = 0x5851F42D4C957F2D :
      local var const uintD multiplier[64/intDsize] =
        { D(0x58,0x51,0xF4,0x2D,) D(0x4C,0x95,0x7F,0x2D,) } ;
      var uintD product[128/intDsize]; # Produkt
      # multiplizieren:
      mulu_2loop_down(&seedMSDptr[64/intDsize],64/intDsize,
                      &multiplier[64/intDsize],64/intDsize,
                      &product[128/intDsize]
                     );
      # letzte 64 Bits holen:
     {var uint32 seed_hi = get_32_Dptr(&product[64/intDsize]);
      var uint32 seed_lo = get_32_Dptr(&product[96/intDsize]);
      seed_lo += 1; if (seed_lo==0) { seed_hi += 1; } # um 1 erhöhen
      # seed neu füllen:
      set_32_Dptr(seedMSDptr,seed_hi); set_32_Dptr(&seedMSDptr[32/intDsize],seed_lo);
      # mittlere 32 Bits als Ergebnis:
      return highlow32(low16(seed_hi),high16(seed_lo));
    }}

# random_UDS(randomstate,MSDptr,len) füllt die UDS MSDptr/len/..
# mit len Zufallsdigits.
# > randomstate: ein Random-State, wird verändert
# > MSDptr/len/..: wo die Zufallsdigits abgelegt werden sollen
# > len: gewünschte Anzahl von Zufallsdigits
  local void random_UDS (object randomstate, uintD* MSDptr, uintC len);
  local void random_UDS(randomstate,ptr,len)
    var object randomstate;
    var uintD* ptr;
    var uintC len;
    { var uintC count;
      dotimesC(count,floor(len,32/intDsize),
        { var uint32 next = random_L(randomstate); # weitere 32/intDsize Digits besorgen
          set_32_Dptr(ptr,next); ptr += 32/intDsize;
        });
      len = len % (32/intDsize); # Anzahl noch fehlender Digits
      if (len>0)
        { var uint32 next =  random_L(randomstate); # weitere 32/intDsize Digits besorgen
          set_max32_Dptr(intDsize*len,ptr,next);
        }
    }

# I_random_I(randomstate,n) liefert zu einem Integer n>0 ein zufälliges
# Integer x mit 0 <= x < n.
# > randomstate: ein Random-State, wird verändert
# can trigger GC
  local object I_random_I (object randomstate, object n);
  local object I_random_I(randomstate,n)
    var object randomstate;
    var object n;
    { var uintD* n_MSDptr;
      var uintC n_len;
      var uintD* n_LSDptr;
      I_to_NDS_nocopy(n, n_MSDptr=,n_len=,n_LSDptr=); # Digit sequence >0 zu n
     {var uintD* MSDptr;
      var uintC len = n_len + ceiling(16,intDsize); # 16 Bits mehr
      if ((intWCsize < 32) && ((uintWC)len < (uintWC)n_len)) { BN_ueberlauf(); }
      {SAVE_NUM_STACK # num_stack retten
       # neue UDS mit len Zufallsdigits bilden:
       num_stack_need(len,MSDptr=,);
       begin_arith_call();
       random_UDS(randomstate,MSDptr,len);
       # und durch n dividieren:
       {var DS q;
        var DS r;
        UDS_divide(MSDptr,len,&MSDptr[(uintP)len], n_MSDptr,n_len,n_LSDptr, &q,&r);
        end_arith_call();
        # Rest in Integer umwandeln:
        {var object result = NUDS_to_I(r.MSDptr,r.len);
         RESTORE_NUM_STACK # num_stack zurück
         return result;
    }}}}}

# F_random_F(randomstate,n) liefert zu einem Float n>0 ein zufälliges
# Float x mit 0 <= x < n.
# > randomstate: ein Random-State, wird verändert
# can trigger GC
  local object F_random_F (object randomstate, object n);
  local object F_random_F(randomstate,n)
    var object randomstate;
    var object n;
    {  pushSTACK(n);
     { var uintL d = F_float_digits(n); # d = (float-digits n) > 0
       # Bilde neue UDS mit d Zufallsbits:
       SAVE_NUM_STACK # num_stack retten
       var uintL len = ceiling(d,intDsize);
       var uintD* MSDptr;
       num_stack_need_1(len,MSDptr=,);
       begin_arith_call();
       random_UDS(randomstate,MSDptr,len); # len (>0) Zufallsdigits
       end_arith_call();
       # von intDsize*ceiling(d/intDsize) auf d Bits herunterschneiden:
       { var uintL dr = d % intDsize; if (dr>0) { MSDptr[0] &= (bit(dr)-1); } }
       # in Integer umwandeln:
      {var object mant = UDS_to_I(MSDptr,len);
       RESTORE_NUM_STACK # num_stack zurück
       # Bilde  Zufalls-Float zwischen 0 und 1
       #        = (scale-float (float Zufalls-Integer,d_Bits n) (- d)) :
       mant = I_F_float_F(mant,STACK_0); # in Float vom Typ von n umwandeln
       pushSTACK(mant);
       {var object minus_d = L_to_I(-d); # (- d)
        mant = popSTACK();
        mant = F_I_scale_float_F(mant,minus_d);
       }
       # Multipliziere es mit n :
       mant = F_F_mal_F(mant,STACK_0);
       # mant ist ein Zufalls-Float >=0, <=n.
       if (eql(mant,popSTACK())) # mit n vergleichen
         # falls (durch Rundung) mant=n, durch 0 ersetzen:
         { mant = I_F_float_F(Fixnum_0,mant); }
       return mant;
    }}}

