View Javadoc
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 }