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
18 package org.apache.commons.rng.core.source32;
19
20 import org.apache.commons.rng.core.util.NumberFactory;
21
22 /**
23 * This abstract class is a base for algorithms from the Xor-Shift-Rotate family of 32-bit
24 * generators with 64-bits of state.
25 *
26 * @see <a href="http://xoshiro.di.unimi.it/">xorshiro / xoroshiro generators</a>
27 * @since 1.3
28 */
29 abstract class AbstractXoRoShiRo64 extends IntProvider {
30 /** Size of the state vector. */
31 private static final int SEED_SIZE = 2;
32
33 // State is maintained using variables rather than an array for performance
34
35 /** State 0 of the generator. */
36 protected int state0;
37 /** State 1 of the generator. */
38 protected int state1;
39
40 /**
41 * Creates a new instance.
42 *
43 * @param seed Initial seed.
44 * If the length is larger than 2, only the first 2 elements will
45 * be used; if smaller, the remaining elements will be automatically
46 * set. A seed containing all zeros will create a non-functional generator.
47 */
48 AbstractXoRoShiRo64(int[] seed) {
49 if (seed.length < SEED_SIZE) {
50 final int[] state = new int[SEED_SIZE];
51 fillState(state, seed);
52 setState(state);
53 } else {
54 setState(seed);
55 }
56 }
57
58 /**
59 * Creates a new instance using a 2 element seed.
60 * A seed containing all zeros will create a non-functional generator.
61 *
62 * @param seed0 Initial seed element 0.
63 * @param seed1 Initial seed element 1.
64 */
65 AbstractXoRoShiRo64(int seed0, int seed1) {
66 state0 = seed0;
67 state1 = seed1;
68 }
69
70 /**
71 * Copies the state from the array into the generator state.
72 *
73 * @param state the new state
74 */
75 private void setState(int[] state) {
76 state0 = state[0];
77 state1 = state[1];
78 }
79
80 /** {@inheritDoc} */
81 @Override
82 protected byte[] getStateInternal() {
83 return composeStateInternal(NumberFactory.makeByteArray(new int[] {state0, state1}),
84 super.getStateInternal());
85 }
86
87 /** {@inheritDoc} */
88 @Override
89 protected void setStateInternal(byte[] s) {
90 final byte[][] c = splitStateInternal(s, SEED_SIZE * 4);
91
92 setState(NumberFactory.makeIntArray(c[0]));
93
94 super.setStateInternal(c[1]);
95 }
96
97 /** {@inheritDoc} */
98 @Override
99 public int next() {
100 final int result = nextOutput();
101
102 final int s0 = state0;
103 int s1 = state1;
104
105 s1 ^= s0;
106 state0 = Integer.rotateLeft(s0, 26) ^ s1 ^ (s1 << 9); // a, b
107 state1 = Integer.rotateLeft(s1, 13); // c
108
109 return result;
110 }
111
112 /**
113 * Use the current state to compute the next output from the generator.
114 * The output function shall vary with respect to different generators.
115 * This method is called from {@link #next()} before the current state is updated.
116 *
117 * @return the next output
118 */
119 protected abstract int nextOutput();
120 }