1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.rng.core.source64;
18
19 import org.apache.commons.rng.core.util.NumberFactory;
20
21 /**
22 * Implement the Small, Fast, Counting (SFC) 64-bit generator of Chris Doty-Humphrey.
23 * The original source is the PractRand test suite by the same author.
24 *
25 * <p>The state size is 256-bits; the period is a minimum of 2<sup>64</sup> and an
26 * average of approximately 2<sup>255</sup>.</p>
27 *
28 * @see <a href="http://pracrand.sourceforge.net/">PractRand</a>
29 * @since 1.3
30 */
31 public class DotyHumphreySmallFastCounting64 extends LongProvider {
32 /** Size of the seed. */
33 private static final int SEED_SIZE = 3;
34
35 /** State a. */
36 private long a;
37 /** State b. */
38 private long b;
39 /** State c. */
40 private long c;
41 /** Counter. */
42 private long counter;
43
44 /**
45 * Creates an instance with the given seed.
46 *
47 * @param seed Initial seed.
48 * If the length is larger than 3, only the first 3 elements will
49 * be used; if smaller, the remaining elements will be automatically set.
50 */
51 public DotyHumphreySmallFastCounting64(long[] seed) {
52 if (seed.length < SEED_SIZE) {
53 final long[] state = new long[SEED_SIZE];
54 fillState(state, seed);
55 setSeedInternal(state);
56 } else {
57 setSeedInternal(seed);
58 }
59 }
60
61 /**
62 * Seeds the RNG.
63 *
64 * @param seed Seed.
65 */
66 private void setSeedInternal(long[] seed) {
67 a = seed[0];
68 b = seed[1];
69 c = seed[2];
70 counter = 1L;
71 for (int i = 0; i < 18; i++) {
72 next();
73 }
74 }
75
76 /** {@inheritDoc} */
77 @Override
78 public final long next() {
79 final long tmp = a + b + counter++;
80 a = b ^ (b >>> 11);
81 b = c + (c << 3);
82 c = Long.rotateLeft(c, 24) + tmp;
83 return tmp;
84 }
85
86 /** {@inheritDoc} */
87 @Override
88 protected byte[] getStateInternal() {
89 return composeStateInternal(NumberFactory.makeByteArray(new long[] {a, b, c, counter}),
90 super.getStateInternal());
91 }
92
93 /** {@inheritDoc} */
94 @Override
95 protected void setStateInternal(byte[] s) {
96 final byte[][] parts = splitStateInternal(s, 4 * 8);
97
98 final long[] tmp = NumberFactory.makeLongArray(parts[0]);
99 a = tmp[0];
100 b = tmp[1];
101 c = tmp[2];
102 counter = tmp[3];
103
104 super.setStateInternal(parts[1]);
105 }
106 }