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.source64; 19 20 import org.apache.commons.rng.JumpableUniformRandomProvider; 21 import org.apache.commons.rng.LongJumpableUniformRandomProvider; 22 import org.apache.commons.rng.UniformRandomProvider; 23 import org.apache.commons.rng.core.util.NumberFactory; 24 25 /** 26 * This abstract class is a base for algorithms from the LXM family of 27 * generators with a 64-bit LCG sub-generator. The class implements 28 * the jump functions. 29 * 30 * @since 1.5 31 */ 32 abstract class AbstractL64 extends LongProvider implements LongJumpableUniformRandomProvider { 33 /** Size of the seed vector. */ 34 private static final int SEED_SIZE = 2; 35 36 /** Per-instance LCG additive parameter (must be odd). 37 * Cannot be final to support RestorableUniformRandomProvider. */ 38 protected long la; 39 /** State of the LCG generator. */ 40 protected long ls; 41 42 /** 43 * Creates a new instance. 44 * 45 * @param seed Initial seed. 46 * If the length is larger than 2, only the first 2 elements will 47 * be used; if smaller, the remaining elements will be automatically 48 * set. 49 * 50 * <p>The 1st element is used to set the LCG increment; the least significant bit 51 * is set to odd to ensure a full period LCG. The 2nd element is used 52 * to set the LCG state.</p> 53 */ 54 AbstractL64(long[] seed) { 55 setState(extendSeed(seed, SEED_SIZE)); 56 } 57 58 /** 59 * Creates a new instance using a 2 element seed. 60 * 61 * <p>The 1st element is used to set the LCG increment; the least significant bit 62 * is set to odd to ensure a full period LCG. The 2nd element is used 63 * to set the LCG state.</p> 64 * 65 * @param seed0 Initial seed element 0. 66 * @param seed1 Initial seed element 1. 67 */ 68 AbstractL64(long seed0, long seed1) { 69 // Additive parameter must be odd 70 la = seed0 | 1; 71 ls = seed1; 72 } 73 74 /** 75 * Creates a copy instance. 76 * 77 * @param source Source to copy. 78 */ 79 AbstractL64(AbstractL64 source) { 80 super(source); 81 la = source.la; 82 ls = source.ls; 83 } 84 85 /** 86 * Copies the state into the generator state. 87 * 88 * @param state the new state 89 */ 90 private void setState(long[] state) { 91 // Additive parameter must be odd 92 la = state[0] | 1; 93 ls = state[1]; 94 } 95 96 /** {@inheritDoc} */ 97 @Override 98 protected byte[] getStateInternal() { 99 return composeStateInternal(NumberFactory.makeByteArray( 100 new long[] {la, ls}), 101 super.getStateInternal()); 102 } 103 104 /** {@inheritDoc} */ 105 @Override 106 protected void setStateInternal(byte[] s) { 107 final byte[][] c = splitStateInternal(s, SEED_SIZE * Long.BYTES); 108 setState(NumberFactory.makeLongArray(c[0])); 109 super.setStateInternal(c[1]); 110 } 111 112 /** 113 * Creates a copy of the UniformRandomProvider and then <em>retreats</em> the state of the 114 * current instance. The copy is returned. 115 * 116 * <p>The jump is performed by advancing the state of the LCG sub-generator by 1 cycle. 117 * The XBG state is unchanged. 118 */ 119 @Override 120 public UniformRandomProvider jump() { 121 final UniformRandomProvider copy = copy(); 122 // Advance the LCG 1 step 123 ls = LXMSupport.M64 * ls + la; 124 resetCachedState(); 125 return copy; 126 } 127 128 /** 129 * Creates a copy of the UniformRandomProvider and then <em>retreats</em> the state of the 130 * current instance. The copy is returned. 131 * 132 * <p>The jump is performed by advancing the state of the LCG sub-generator by 133 * 2<sup>32</sup> cycles. The XBG state is unchanged. 134 */ 135 @Override 136 public JumpableUniformRandomProvider longJump() { 137 final JumpableUniformRandomProvider copy = copy(); 138 // Advance the LCG 2^32 steps 139 ls = LXMSupport.M64P * ls + LXMSupport.C64P * la; 140 resetCachedState(); 141 return copy; 142 } 143 144 /** 145 * Create a copy. 146 * 147 * @return the copy 148 */ 149 abstract AbstractL64 copy(); 150 }