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.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 }