Packages

otpbp

7.3.2
7.18.0 7.16.1 7.15.0 7.14.0 7.13.0 7.12.0 7.11.0 7.10.2 7.9.3 7.9.2 7.9.1 7.8.7 7.8.6 7.8.5 7.8.4 7.7.1 7.7.0 7.6.3 7.6.2 7.6.1 7.6.0 7.5.1 7.5.0 7.4.0 7.3.4 7.3.3 7.3.2 7.3.1 7.3.0 7.2.0 7.1.1 7.1.0 7.0.4 7.0.3 7.0.2 7.0.1 6.26.0 6.25.0 6.24.0 6.23.0 6.22.2 6.21.3 6.21.2 6.21.1 6.20.2 6.19.1 6.19.0 6.18.3 6.18.2 6.18.1 6.18.0 6.17.1 6.17.0 6.16.0 6.15.4 6.15.3 6.15.2 6.15.1 6.15.0 6.14.0 6.13.5 6.13.4 6.13.3 6.13.2 6.13.1 6.13.0 6.12.0 6.11.2 6.11.1 6.10.0 6.9.2 6.9.1 6.9.0 6.8.0 6.7.1 6.7.0 6.6.4 6.6.3 6.6.2 6.6.1 6.6.0 6.5.0 6.4.0 6.3.3 6.3.2 6.3.1 6.3.0 6.2.1 6.2.0 6.1.0 6.0.0 5.39.0 5.38.0 5.37.0 5.36.0 5.35.2 5.34.3 5.34.2 5.34.1 5.33.1 5.32.1 5.32.0 5.31.3 5.31.2 5.31.1 5.31.0 5.30.1 5.30.0 5.29.0 5.28.4 5.28.3 5.28.2 5.28.1 5.28.0 5.27.0 5.26.5 5.26.4 5.26.3 5.26.2 5.26.1 5.26.0 5.25.0 5.24.2 5.24.1 5.23.0 5.22.2 5.22.1 5.22.0 5.21.0 5.20.1 5.20.0 5.19.4 5.19.3 5.19.2 5.19.1 5.19.0 5.18.0 5.17.0 5.16.3 5.16.1 5.16.0 5.15.1 5.15.0 5.14.0 5.13.1 5.13.0 5.12.1 5.12.0 5.11.2 5.11.1 5.10.1 5.10.0 5.9.0 5.8.0 5.7.0 5.6.1 5.6.0 5.5.0 5.4.2 5.4.1 5.4.0 5.3.0 5.2.2 5.2.1 5.2.0 5.1.2 5.1.1 4.79.0 4.78.0 4.77.0 4.76.2 4.75.3 4.75.2 4.75.1 4.74.0 4.73.1 4.73.0 4.72.3 4.72.2 4.72.1 4.72.0 4.71.1 4.71.0 4.70.0 4.69.4 4.69.3 4.69.2 4.69.1 4.69.0 4.68.0 4.67.5 4.67.4 4.67.3 4.67.2 4.67.0 4.66.0 4.65.2 4.65.1 4.64.0 4.63.2 4.63.1 4.63.0 4.62.0 4.61.1 4.61.0 4.60.4 4.60.3 4.60.2 4.60.1 4.60.0 4.59.0 4.58.0 4.57.2 4.57.1 4.57.0 4.56.2 4.56.1 4.56.0 4.55.0 4.54.0 4.53.0 4.52.1 4.52.0 4.51.3 4.51.2 4.51.0 4.50.0 4.49.3 4.49.2

OTP backports

Current section

Files

Jump to
otpbp src otpbp_rand.erl
Raw

src/otpbp_rand.erl

-module(otpbp_rand).
-ifndef(HAVE_rand__uniform_real_0).
% OTP 21.0
-export([uniform_real/0]).
-endif.
-ifndef(HAVE_rand__uniform_real_s_1).
% OTP 21.0
-export([uniform_real_s/1]).
-endif.
-ifndef(HAVE_rand__splitmix64_next_1).
% OTP 25.0
-export([splitmix64_next/1]).
-endif.
-ifndef(HAVE_rand__exsp_next_1).
% OTP 25.0
-export([exsp_next/1]).
-endif.
-ifndef(HAVE_rand__exsp_jump_1).
% OTP 25.0
-export([exsp_jump/1]).
-endif.
-ifndef(HAVE_rand__mwc59_1).
% OTP 25.0
-export([mwc59/1]).
-endif.
-ifndef(HAVE_rand__mwc59_value32_1).
% OTP 25.0
-export([mwc59_value32/1]).
-endif.
-ifndef(HAVE_rand__mwc59_value_1).
% OTP 25.0
-export([mwc59_value/1]).
-endif.
-ifndef(HAVE_rand__mwc59_float_1).
% OTP 25.0
-export([mwc59_float/1]).
-endif.
-ifndef(HAVE_rand__mwc59_seed_0).
% OTP 25.0
-export([mwc59_seed/0]).
-endif.
-ifndef(HAVE_rand__mwc59_seed_1).
% OTP 25.0
-export([mwc59_seed/1]).
-endif.
-ifndef(HAVE_rand__bytes_1).
% OTP 24.0
-export([bytes/1]).
-endif.
-ifndef(HAVE_rand__bytes_s_2).
% OTP 24.0
-export([bytes_s/2]).
-endif.
-ifndef(HAVE_rand__uniform_real_0).
-ifdef(HAVE_rand__uniform_real_s_1).
-import(rand, [uniform_real_s/1]).
-endif.
-endif.
-ifndef(HAVE_rand__exsp_jump_1).
-ifdef(HAVE_rand__exsp_next_1).
-import(rand, [exsp_next/1]).
-endif.
-endif.
-ifndef(HAVE_rand__bytes_1).
-ifdef(HAVE_rand__bytes_s_2).
-import(rand, [bytes_s/2]).
-endif.
-endif.
-define(SEED_DICT, rand_seed).
-define(BIT(Bits), (1 bsl (Bits))).
-define(MASK(Bits), (?BIT(Bits) - 1)).
-define(MASK(Bits, X), ((X) band ?MASK(Bits))).
-define(BSL(Bits, X, N), (?MASK((Bits) - (N), (X)) bsl (N))).
-define(MWC59_XS1, 4).
-define(MWC59_XS2, 27).
-ifndef(HAVE_rand__bytes_1).
bytes(N) ->
{Bytes, State} = bytes_s(N, seed_get()),
seed_put(State),
Bytes.
-ifndef(NEED_seed_get_0).
-define(NEED_seed_get_0, true).
-endif.
-ifndef(NEED_seed_put_1).
-define(NEED_seed_put_1, true).
-endif.
-endif.
-ifndef(HAVE_rand__bytes_s_2).
bytes_s(N, {#{bits := Bits, next := Next} = AlgHandler, R}) when is_integer(N), 0 =< N ->
bytes_r(N, AlgHandler, Next, R, Bits, maps:get(weak_low_bits, AlgHandler, 0));
bytes_s(N, {#{max := Mask, next := Next} = AlgHandler, R}) when is_integer(N), 0 =< N, ?MASK(58) =< Mask ->
%% Old spec - assume 58 bits and 2 weak low bits
%% giving 56 bits i.e precisely 7 bytes per generated number
bytes_r(N, AlgHandler, Next, R, 58, 2).
-compile({inline, bytes_r/6}).
bytes_r(N, AlgHandler, Next, R, Bits, WeakLowBits) ->
%% We use whole bytes from each generator word,
%% GoodBytes: that number of bytes
GoodBytes = (Bits - WeakLowBits) bsr 3,
GoodBits = GoodBytes bsl 3,
%% Shift: how many bits of each generator word to waste by shifting right - we use the bits from the big end
bytes_r(N, AlgHandler, Next, R, <<>>, GoodBytes, GoodBits, Bits - GoodBits).
bytes_r(N0, AlgHandler, Next, R0, Bytes0, GoodBytes, GoodBits, Shift) when GoodBytes < N0 ->
{V, R1} = Next(R0),
bytes_r(N0 - GoodBytes, AlgHandler, Next, R1, <<Bytes0/binary, (V bsr Shift):GoodBits>>, GoodBytes, GoodBits, Shift);
bytes_r(N, AlgHandler, Next, R0, Bytes, _GoodBytes, GoodBits, _Shift) ->
{V, R1} = Next(R0),
Bits = N bsl 3,
%% Use the big end bits
{<<Bytes/binary, (V bsr (GoodBits - Bits)):Bits>>, {AlgHandler, R1}}.
-endif.
-ifndef(HAVE_rand__uniform_real_0).
uniform_real() ->
{X, Seed} = uniform_real_s(seed_get()),
seed_put(Seed),
X.
-ifndef(NEED_seed_get_0).
-define(NEED_seed_get_0, true).
-endif.
-ifndef(NEED_seed_put_1).
-define(NEED_seed_put_1, true).
-endif.
-endif.
-ifndef(HAVE_rand__uniform_real_s_1).
-define(BC(V, N), bc((V), ?BIT((N) - 1), N)).
uniform_real_s({#{next := Next} = Alg, R0}) ->
{V1, R1} = Next(R0),
uniform_real_s(Alg, V1, R1, Next).
-compile({inline, uniform_real_s/5}).
uniform_real_s(#{bits := Bits} = Alg, V1, R1, Next) ->
case V1 bsr (Bits - 56) of
M1 when ?BIT(55) =< M1 -> %% We have 56 bits - waste 3
{(M1 bsr 3) * math:pow(2.0, -53), {Alg, R1}};
M1 when ?BIT(54) =< M1 -> %% We have 55 bits - waste 2
{(M1 bsr 2) * math:pow(2.0, -54), {Alg, R1}};
M1 when ?BIT(53) =< M1 -> %% We have 54 bits - waste 1
{(M1 bsr 1) * math:pow(2.0, -55), {Alg, R1}};
M1 when ?BIT(52) =< M1 -> %% We have 53 bits - use all
{M1 * math:pow(2.0, -56), {Alg, R1}};
M1 -> %% Need more bits
{V2, R2} = Next(R1),
uniform_real_s(Alg, Next, M1, -56, R2, V2, Bits)
end;
uniform_real_s(#{max := _} = Alg, V1, R1, Next) ->
case ?MASK(56, V1) of
M1 when ?BIT(55) =< M1 -> %% We have 56 bits - waste 3
{(M1 bsr 3) * math:pow(2.0, -53), {Alg, R1}};
M1 when ?BIT(54) =< M1 -> %% We have 55 bits - waste 2
{(M1 bsr 2) * math:pow(2.0, -54), {Alg, R1}};
M1 when ?BIT(53) =< M1 -> %% We have 54 bits - waste 1
{(M1 bsr 1) * math:pow(2.0, -55), {Alg, R1}};
M1 when ?BIT(52) =< M1 -> %% We have 53 bits - use all
{M1 * math:pow(2.0, -56), {Alg, R1}};
M1 -> %% Need more bits
{V2, R2} = Next(R1),
uniform_real_s(Alg, Next, M1, -56, R2, V2, 56)
end.
uniform_real_s(Alg, _Next, M0, -1064, R1, V1, Bits) -> % 19*56
B0 = (53 - ?BC(M0, 52)), % Missing bits
{(((M0 bsl B0) bor (V1 bsr (Bits - B0))) * math:pow(2.0, -1064 - B0)), {Alg, R1}};
uniform_real_s(Alg, _Next, M0, BitNo, R1, V1, Bits) when ?BIT(51) =< M0 ->
{(((M0 bsl 1) bor (V1 bsr (Bits - 1))) * math:pow(2.0, BitNo - 1)), {Alg, R1}};
uniform_real_s(Alg, _Next, M0, BitNo, R1, V1, Bits) when ?BIT(50) =< M0 ->
{(((M0 bsl 2) bor (V1 bsr (Bits - 2))) * math:pow(2.0, BitNo - 2)), {Alg, R1}};
uniform_real_s(Alg, _Next, M0, BitNo, R1, V1, Bits) when ?BIT(49) =< M0 ->
{(((M0 bsl 3) bor (V1 bsr (Bits - 3))) * math:pow(2.0, BitNo - 3)), {Alg, R1}};
uniform_real_s(Alg, Next, 0, BitNo, R1, V1, Bits) ->
case V1 bsr (Bits - 56) of
M1 when ?BIT(55) =< M1 -> %% We have 56 bits - waste 3
{(M1 bsr 3) * math:pow(2.0, BitNo - 53), {Alg, R1}};
M1 when ?BIT(54) =< M1 -> %% We have 55 bits - waste 2
{(M1 bsr 2) * math:pow(2.0, BitNo - 54), {Alg, R1}};
M1 when ?BIT(53) =< M1 -> %% We have 54 bits - waste 1
{(M1 bsr 1) * math:pow(2.0, BitNo - 55), {Alg, R1}};
M1 when ?BIT(52) =< M1 -> %% We have 53 bits - use all
{M1 * math:pow(2.0, BitNo - 56), {Alg, R1}};
M1 when BitNo =/= -1008; ?BIT(42) =< M1 -> %% Need more bits; We have 43 bits - get the last bits
uniform_real_s(Alg, Next, M1, BitNo - 56, R1);
_ -> uniform_real_s({Alg, R1})
end;
uniform_real_s(Alg, _Next, M0, BitNo, R1, V1, Bits) ->
%% Fill up to 53 bits
B0 = 53 - ?BC(M0, 49), % Number of bits we need to append
{(((M0 bsl B0) bor (V1 bsr (Bits - B0))) * math:pow(2.0, BitNo - B0)), {Alg, R1}}.
uniform_real_s(Alg, Next, M0, BitNo, R0) ->
{V1, R1} = Next(R0),
case Alg of
#{bits := Bits} -> uniform_real_s(Alg, Next, M0, BitNo, R1, V1, Bits);
#{max := _} -> uniform_real_s(Alg, Next, M0, BitNo, R1, ?MASK(56, V1), 56)
end.
bc(V, B, N) when B =< V -> N;
bc(V, B, N) -> bc(V, B bsr 1, N - 1).
-endif.
-ifndef(HAVE_rand__splitmix64_next_1).
splitmix64_next(X_0) ->
X = ?MASK(64, X_0 + 16#9e3779b97f4a7c15),
Z_0 = ?MASK(64, (X bxor (X bsr 30)) * 16#bf58476d1ce4e5b9),
Z_1 = ?MASK(64, (Z_0 bxor (Z_0 bsr 27)) * 16#94d049bb133111eb),
{?MASK(64, Z_1 bxor (Z_1 bsr 31)), X}.
-endif.
-ifndef(HAVE_rand__exsp_next_1).
-define(exs_next(S0, S1, S1_b),
begin
S1_b = ?MASK(58, S1) bxor ?BSL(58, S1, 24),
S1_b bxor S0 bxor (S1_b bsr 11) bxor (S0 bsr 41)
end).
exsp_next([S1|S0]) ->
S0_1 = ?MASK(58, S0),
NewS1 = ?exs_next(S0_1, S1, S1_b),
{?MASK(58, S0_1 + NewS1), [S0_1|NewS1]}.
-endif.
-ifndef(HAVE_rand__exsp_jump_1).
-define(JUMPCONST1, 16#02f8ea6bc32c797).
-define(JUMPCONST2, 16#345d2a0f85f788c).
-define(JUMPELEMLEN, 58).
exsp_jump(S) ->
{S1, AS1} = exsplus_jump(S, [0|0], ?JUMPCONST1, ?JUMPELEMLEN),
{_, AS2} = exsplus_jump(S1, AS1, ?JUMPCONST2, ?JUMPELEMLEN),
AS2.
-dialyzer({no_improper_lists, exsplus_jump/4}).
exsplus_jump(S, AS, _, 0) -> {S, AS};
exsplus_jump(S, [AS0|AS1], J, N) ->
{_, NS} = exsp_next(S),
exsplus_jump(NS,
case ?MASK(1, J) of
1 ->
[S0|S1] = S,
[AS0 bxor S0|AS1 bxor S1];
0 -> [AS0|AS1]
end,
J bsr 1,
N - 1).
-endif.
-ifndef(HAVE_rand__mwc59_1).
-define(MWC59_A, 16#7fa6502).
-define(MWC59_B, 32).
mwc59(CX0) ->
CX = ?MASK(59, CX0),
?MWC59_A * ?MASK(?MWC59_B, CX) + CX bsr ?MWC59_B.
-endif.
-ifndef(HAVE_rand__mwc59_value32_1).
-define(MWC59_XS, 8).
mwc59_value32(CX1) ->
CX = ?MASK(32, CX1),
CX bxor ?BSL(32, CX, ?MWC59_XS).
-endif.
-ifndef(HAVE_rand__mwc59_value_1).
mwc59_value(CX1) ->
CX = ?MASK(59, CX1),
CX2 = CX bxor ?BSL(59, CX, ?MWC59_XS1),
CX2 bxor ?BSL(59, CX2, ?MWC59_XS2).
-endif.
-ifndef(HAVE_rand__mwc59_float_1).
-define(TWO_POW_MINUS53, 1.11022302462515657e-16).
mwc59_float(CX1) ->
CX = ?MASK(53, CX1),
CX2 = CX bxor ?BSL(53, CX, ?MWC59_XS1),
(CX2 bxor ?BSL(53, CX2, ?MWC59_XS2)) * ?TWO_POW_MINUS53.
-endif.
-ifndef(HAVE_rand__mwc59_seed_0).
mwc59_seed() ->
{A1, A2, A3} = default_seed(),
hash58(A1) bxor hash58(A2) bxor hash58(A3) + 1.
-compile({inline, default_seed/0}).
default_seed() -> {erlang:phash2([{node(), self()}]), erlang:system_time(), erlang:unique_integer()}.
-ifndef(NEED_hash58_1).
-define(NEED_hash58_1, true).
-endif.
-endif.
-ifndef(HAVE_rand__mwc59_seed_1).
mwc59_seed(S) when is_integer(S), 0 =< S, S =< ?MASK(58) -> hash58(S) + 1.
-ifndef(NEED_hash58_1).
-define(NEED_hash58_1, true).
-endif.
-endif.
-ifdef(NEED_seed_get_0).
-define(DEFAULT_ALG_HANDLER, exrop).
seed_get() ->
case get(?SEED_DICT) of
undefined -> rand:seed(?DEFAULT_ALG_HANDLER);
Old -> Old % no type checking here
end.
-endif.
-ifdef(NEED_seed_put_1).
seed_put(Seed) ->
put(?SEED_DICT, Seed),
Seed.
-endif.
-ifdef(NEED_hash58_1).
hash58(X) ->
X0 = ?MASK(58, X),
X1 = ?MASK(58, (X0 bxor (X0 bsr 29)) * 16#351afd7ed558ccd),
X2 = ?MASK(58, (X1 bxor (X1 bsr 29)) * 16#0ceb9fe1a85ec53),
X2 bxor (X2 bsr 29).
-endif.