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 }