How to make an infinite splittable stream of non-colliding numbers from one seed cheap?

I need a function split : Word64 -> (Word64, Word64)that takes any Word64 and breaks it into two different Word64 dictionaries so that I can continue to split children and grandchildren in any arbitrary order, avoiding a collision. That is, for any pair of sa, sbconsecutive seed cleavages (for example, sa = fst.split.fst.split$ seed) it sashould be different from sbwith a coefficient> 99.99%.

I thought about using the mating function, but this makes the children exponentially larger than the parents, so after a few sections there is an integer overflow. I need something that basically sends any value in the space of possible Word64 bits to two other values ​​in a semi-random manner. In addition, I need it to be as quick and easy as possible. The fewer instructions, the better. This is probably a very stupid calculation that I miss.

What can be used here?

Disclaimer: I used to ask similar questions, but now I finally understand the problem better and know exactly what I need.

+4
source share
2 answers

, , . xorshift, , , .

xorshift *, C:

#include <stdint.h>

uint64_t x; /* The state must be seeded with a nonzero value. */

uint64_t xorshift64star(void) {
    x ^= x >> 12; // a
    x ^= x << 25; // b
    x ^= x >> 27; // c
    return x * UINT64_C(2685821657736338717);
}

wikipedia :

xorshift * xorshift ( ) .

, :

  • node x.

  • x .

    • , return x; ( xorshift)

    • , , .

node u , v w.

  • v w, , , xorshift, xorshift * w, v.

  • w v, .

  • node . , u v w, (, u).

+2

, : , .

\x -> (x*3+1, x*3+2). modulo-2 ^ 64 . . , 3 . , 3^n 2*3^n, , n.

, :

import Control.Monad
import Data.Int
import Text.Printf
import System.Random (randomRIO)
import qualified Data.Set as Set

split :: Int32 -> (Int32, Int32)
split x = (x * 3 + 1, x * 3 + 2)

bools bias n =
  replicateM n (randomRIO (0, 1.0) >>= \x -> if x < bias then return False else return True)

gogo bias =
  bools bias 100000 >>= \l -> do
    let things = scanl (\x b -> if b then fst (split x) else snd (split x)) 0 l
    printf "%.2f %d %d\n" bias (length things) (length $ Set.toList (Set.fromList things))
    return things

main = do
  things <- mapM gogo [0.0 :: Double, 0.05 .. 1]
  printf "all  %d %d\n" (length $ concat things) (length $ Set.toList (Set.fromList $ concat things))



0.00 100001 100001
0.05 100001 100001
0.10 100001 100001
0.15 100001 100001
0.20 100001 100001
0.25 100001 100000
0.30 100001 99997
0.35 100001 99998
0.40 100001 99999
0.45 100001 99999
0.50 100001 100001
0.55 100001 100000
0.60 100001 100001
0.65 100001 100001
0.70 100001 99998
0.75 100001 99999
0.80 100001 100001
0.85 100001 100001
0.90 100001 100001
0.95 100001 100001
1.00 100001 100001
all  2100021 2099351

, , , .

+2

All Articles