Skip to content

Commit 3ace5c9

Browse files
committed
Try dedicated shuffle_mwc59
1 parent 7a0c4af commit 3ace5c9

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

lib/stdlib/src/rand.erl

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,9 @@ and the [`NewState`](`t:state/0`).
18321832
when
18331833
List :: list(),
18341834
State :: state().
1835+
shuffle_s(List, {#{type:=mwc59} = AlgHandler, CX0}) ->
1836+
{ShuffledList, _P1, CX1} = shuffle_s_mwc59(List, CX0),
1837+
{ShuffledList, {AlgHandler, CX1}};
18351838
shuffle_s(List, {AlgHandler, R0})
18361839
when is_list(List) ->
18371840
[P0|S0] = shuffle_init_bitstream(R0, AlgHandler),
@@ -3239,6 +3242,83 @@ hash58(X) ->
32393242
X2 = ?MASK(58, (X1 bxor (X1 bsr 29)) * 16#0ceb9fe1a85ec53),
32403243
X2 bxor (X2 bsr 29).
32413244

3245+
%% -------
3246+
3247+
shuffle_s_mwc59(List, S) ->
3248+
shuffle_mwc59_r(List, [], 1, S).
3249+
3250+
%% Leaf cases - random permutations for 0..3 elements
3251+
shuffle_mwc59_r([], Acc, P, S) ->
3252+
{Acc, P, S};
3253+
shuffle_mwc59_r([X], Acc, P, S) ->
3254+
{[X | Acc], P, S};
3255+
shuffle_mwc59_r([X, Y], Acc, P, S) ->
3256+
shuffle_mwc59_r_2(X, Acc, P, S, Y);
3257+
shuffle_mwc59_r([X, Y, Z], Acc, P, S) ->
3258+
shuffle_mwc59_r_3(X, Acc, P, S, Y, Z);
3259+
%% General case - split and recursive shuffle
3260+
shuffle_mwc59_r([_, _, _ | _] = List, Acc, P, S) ->
3261+
%% P and S is bitstream cache and state
3262+
shuffle_mwc59_r(List, Acc, P, S, [], [], [], []).
3263+
%%
3264+
%% Split L into 4 random subsets
3265+
%%
3266+
shuffle_mwc59_r([], Acc0, P0, S0, Zero, One, Two, Three) ->
3267+
%% Split done, recursively shuffle the splitted lists onto Acc
3268+
{Acc1, P1, S1} = shuffle_mwc59_r(Zero, Acc0, P0, S0),
3269+
{Acc2, P2, S2} = shuffle_mwc59_r(One, Acc1, P1, S1),
3270+
{Acc3, P3, S3} = shuffle_mwc59_r(Two, Acc2, P2, S2),
3271+
shuffle_mwc59_r(Three, Acc3, P3, S3);
3272+
shuffle_mwc59_r([X | L], Acc, P0, S, Zero, One, Two, Three)
3273+
when is_integer(P0), 3 < P0, P0 =< ?MASK(59) ->
3274+
P1 = P0 bsr 2,
3275+
case P0 band 3 of
3276+
0 -> shuffle_mwc59_r(L, Acc, P1, S, [X | Zero], One, Two, Three);
3277+
1 -> shuffle_mwc59_r(L, Acc, P1, S, Zero, [X | One], Two, Three);
3278+
2 -> shuffle_mwc59_r(L, Acc, P1, S, Zero, One, [X | Two], Three);
3279+
3 -> shuffle_mwc59_r(L, Acc, P1, S, Zero, One, Two, [X | Three])
3280+
end;
3281+
shuffle_mwc59_r([_ | _] = L, Acc, _P, S0, Zero, One, Two, Three) ->
3282+
S1 = ?mwc59(S0, C, D),
3283+
P = ?mwc59_value(S1, Tmp) bor ?BIT(58),
3284+
shuffle_mwc59_r(L, Acc, P, S1, Zero, One, Two, Three).
3285+
3286+
%% Permute 2 elements
3287+
shuffle_mwc59_r_2(X, Acc, P, S, Y)
3288+
when is_integer(P), 1 < P, P =< ?MASK(59) ->
3289+
{case P band 1 of
3290+
0 -> [Y, X | Acc];
3291+
1 -> [X, Y | Acc]
3292+
end, P bsr 1, S};
3293+
shuffle_mwc59_r_2(X, Acc, _P, S0, Y) ->
3294+
S1 = ?mwc59(S0, C, D),
3295+
P = ?mwc59_value(S1, Tmp) bor ?BIT(58),
3296+
shuffle_mwc59_r_2(X, Acc, P, S1, Y).
3297+
3298+
%% Permute 3 elements
3299+
%%
3300+
%% Uses 3 random bits per iteration with a probability of 1/4
3301+
%% to reject and retry, which on average is 3 * 4/3
3302+
%% (infinite sum of (1/4)^k) = 4 bits per permutation
3303+
shuffle_mwc59_r_3(X, Acc, P0, S, Y, Z)
3304+
when is_integer(P0), 7 < P0, P0 =< ?MASK(59) ->
3305+
P1 = P0 bsr 3,
3306+
case P0 band 7 of
3307+
0 -> {[Z, Y, X | Acc], P1, S};
3308+
1 -> {[Y, Z, X | Acc], P1, S};
3309+
2 -> {[Z, X, Y | Acc], P1, S};
3310+
3 -> {[X, Z, Y | Acc], P1, S};
3311+
4 -> {[Y, X, Z | Acc], P1, S};
3312+
5 -> {[X, Y, Z | Acc], P1, S};
3313+
_ -> % Reject and retry
3314+
shuffle_mwc59_r_3(X, Acc, P1, S, Y, Z)
3315+
end;
3316+
shuffle_mwc59_r_3(X, Acc, _P, S0, Y, Z) ->
3317+
S1 = ?mwc59(S0, C, D),
3318+
P = ?mwc59_value(S1, Tmp) bor ?BIT(58),
3319+
shuffle_mwc59_r_3(X, Acc, P, S1, Y, Z).
3320+
3321+
32423322
%% =====================================================================
32433323
%% Mask and fill state list, ensure not all zeros
32443324
%% =====================================================================

0 commit comments

Comments
 (0)