-module(prng_ffi). -export([new_seed/1, random_int/3, random_float/3]). new_seed(From) -> State0 = next(0), State1 = truncate_32(State0 + From), next(State1). seed_to_int(State) -> ShiftedState = urs(State, urs(State, 28) + 4), Word = trunc(expand_to_64(State bxor ShiftedState) * 277_803_737.0), truncate_32(urs(Word, 22) bxor Word). random_float(Seed, From, To) -> NewSeed = next(Seed), FirstNumber = seed_to_int(Seed), SecondNumber = seed_to_int(NewSeed), High = FirstNumber band 16#03FFFFFF, Low = SecondNumber band 16#07FFFFFF, Value = ((High * 134217728.0) + Low) / 9007199254740992.0, Range = To - From, Scaled = Value * Range + From, {Scaled, next(NewSeed)}. random_int(Seed, From, To) -> Range = To - From + 1, IsPowerOf2 = ((Range - 1) band Range) =:= 0, case IsPowerOf2 of true -> Number = truncate_32(seed_to_int(Seed) band (Range - 1)), {Number + From, next(Seed)}; false -> Threshold = truncate_32(truncate_32(-Range) rem Range), account_for_bias(Threshold, Seed, From, Range) end. account_for_bias(Threshold, Seed, From, Range) -> X = seed_to_int(Seed), IterationSeed = next(Seed), case X < Threshold of true -> account_for_bias(Threshold, IterationSeed, From, Range); false -> {From + (X rem Range), IterationSeed} end. -define(STEP, 1_013_904_223). next(State) -> NewState = urs((State * 1_664_525.0) + ?STEP, 0), NewState. % unsigned right shift urs(Number, By) -> Left = 32 - By, <> = truncate_32(Number, to_bit), Remaining. expand_to_64(Number) -> <> = <>, <> = NumberBits, Pad = case First of 1 -> <<-1:32>>; _ -> <<0:32>> end, <> = <>, Result. truncate_32(Number) -> truncate_32(Number, to_int). truncate_32(Number, Mode) when is_float(Number) -> truncate_32(trunc(Number), Mode); truncate_32(Number, to_int) -> Number band 4294967295; truncate_32(Number, to_bit) -> Truncated = truncate_32(Number, to_int), <>.