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 }