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 128-bit LCG sub-generator. The class implements 28 * the jump functions. 29 * 30 * @since 1.5 31 */ 32 abstract class AbstractL128 extends LongProvider implements LongJumpableUniformRandomProvider { 33 /** Size of the seed vector. */ 34 private static final int SEED_SIZE = 4; 35 /** Low half of 128-bit LCG multiplier. */ 36 private static final long ML = LXMSupport.M128L; 37 38 /** High half of the 128-bit per-instance LCG additive parameter. 39 * Cannot be final to support RestorableUniformRandomProvider. */ 40 protected long lah; 41 /** Low half of the 128-bit per-instance LCG additive parameter (must be odd). 42 * Cannot be final to support RestorableUniformRandomProvider. */ 43 protected long lal; 44 /** High half of the 128-bit state of the LCG generator. */ 45 protected long lsh; 46 /** Low half of the 128-bit state of the LCG generator. */ 47 protected long lsl; 48 49 /** 50 * Creates a new instance. 51 * 52 * @param seed Initial seed. 53 * If the length is larger than 4, only the first 4 elements will 54 * be used; if smaller, the remaining elements will be automatically 55 * set. 56 * 57 * <p>The 1st and 2nd elements are used to set the LCG increment; the least significant bit 58 * is set to odd to ensure a full period LCG. The 3rd and 4th elements are used 59 * to set the LCG state.</p> 60 */ 61 AbstractL128(long[] seed) { 62 setState(extendSeed(seed, SEED_SIZE)); 63 } 64 65 /** 66 * Creates a new instance using a 4 element seed. 67 * 68 * <p>The 1st and 2nd elements are used to set the LCG increment; the least significant bit 69 * is set to odd to ensure a full period LCG. The 3rd and 4th elements are used 70 * to set the LCG state.</p> 71 * 72 * @param seed0 Initial seed element 0. 73 * @param seed1 Initial seed element 1. 74 * @param seed2 Initial seed element 2. 75 * @param seed3 Initial seed element 3. 76 */ 77 AbstractL128(long seed0, long seed1, long seed2, long seed3) { 78 lah = seed0; 79 // Additive parameter must be odd 80 lal = seed1 | 1; 81 lsh = seed2; 82 lsl = seed3; 83 } 84 85 /** 86 * Creates a copy instance. 87 * 88 * @param source Source to copy. 89 */ 90 AbstractL128(AbstractL128 source) { 91 super(source); 92 lah = source.lah; 93 lal = source.lal; 94 lsh = source.lsh; 95 lsl = source.lsl; 96 } 97 98 /** 99 * Copies the state into the generator state. 100 * 101 * @param state the new state 102 */ 103 private void setState(long[] state) { 104 lah = state[0]; 105 // Additive parameter must be odd 106 lal = state[1] | 1; 107 lsh = state[2]; 108 lsl = state[3]; 109 } 110 111 /** {@inheritDoc} */ 112 @Override 113 protected byte[] getStateInternal() { 114 return composeStateInternal(NumberFactory.makeByteArray( 115 new long[] {lah, lal, lsh, lsl}), 116 super.getStateInternal()); 117 } 118 119 /** {@inheritDoc} */ 120 @Override 121 protected void setStateInternal(byte[] s) { 122 final byte[][] c = splitStateInternal(s, SEED_SIZE * Long.BYTES); 123 setState(NumberFactory.makeLongArray(c[0])); 124 super.setStateInternal(c[1]); 125 } 126 127 /** 128 * Creates a copy of the UniformRandomProvider and then <em>retreats</em> the state of the 129 * current instance. The copy is returned. 130 * 131 * <p>The jump is performed by advancing the state of the LCG sub-generator by 1 cycle. 132 * The XBG state is unchanged. 133 */ 134 @Override 135 public UniformRandomProvider jump() { 136 final UniformRandomProvider copy = copy(); 137 // Advance the LCG 1 step. 138 // The LCG is, in effect, "s = m * s + a" where m = ((1LL << 64) + ML) 139 final long sh = lsh; 140 final long sl = lsl; 141 final long u = ML * sl; 142 // High half 143 lsh = ML * sh + LXMSupport.unsignedMultiplyHigh(ML, sl) + sl + lah + 144 // Carry propagation 145 LXMSupport.unsignedAddHigh(u, lal); 146 // Low half 147 lsl = u + lal; 148 resetCachedState(); 149 return copy; 150 } 151 152 /** 153 * Creates a copy of the UniformRandomProvider and then <em>retreats</em> the state of the 154 * current instance. The copy is returned. 155 * 156 * <p>The jump is performed by advancing the state of the LCG sub-generator by 157 * 2<sup>64</sup> cycles. The XBG state is unchanged. 158 */ 159 @Override 160 public JumpableUniformRandomProvider longJump() { 161 final JumpableUniformRandomProvider copy = copy(); 162 // Advance the LCG 2^64 steps 163 // s = m' * s + c' * c 164 // Specialised routine given M128PL=1, C128PL=0 and many terms 165 // can be dropped as the low half is unchanged and there is no carry 166 // sh = m'l * sh // sh 167 // + high(m'l * sl) // dropped as m'l=1 and there is no high part 168 // + m'h * sl 169 // + c'l * ah // dropped as c'l=0 170 // + high(c'l * ah) // dropped as c'l=0 171 // + c'h * al 172 // sl = m'l * sl + c'l * al 173 // = sl 174 lsh = lsh + LXMSupport.M128PH * lsl + LXMSupport.C128PH * lal; 175 resetCachedState(); 176 return copy; 177 } 178 179 /** 180 * Create a copy. 181 * 182 * @return the copy 183 */ 184 abstract AbstractL128 copy(); 185 }