AbstractL64.java

  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. package org.apache.commons.rng.core.source64;

  18. import org.apache.commons.rng.JumpableUniformRandomProvider;
  19. import org.apache.commons.rng.LongJumpableUniformRandomProvider;
  20. import org.apache.commons.rng.UniformRandomProvider;
  21. import org.apache.commons.rng.core.util.NumberFactory;

  22. /**
  23.  * This abstract class is a base for algorithms from the LXM family of
  24.  * generators with a 64-bit LCG sub-generator. The class implements
  25.  * the jump functions.
  26.  *
  27.  * @since 1.5
  28.  */
  29. abstract class AbstractL64 extends LongProvider implements LongJumpableUniformRandomProvider {
  30.     /** Size of the seed vector. */
  31.     private static final int SEED_SIZE = 2;

  32.     /** Per-instance LCG additive parameter (must be odd).
  33.      * Cannot be final to support RestorableUniformRandomProvider. */
  34.     protected long la;
  35.     /** State of the LCG generator. */
  36.     protected long ls;

  37.     /**
  38.      * Creates a new instance.
  39.      *
  40.      * @param seed Initial seed.
  41.      * If the length is larger than 2, only the first 2 elements will
  42.      * be used; if smaller, the remaining elements will be automatically
  43.      * set.
  44.      *
  45.      * <p>The 1st element is used to set the LCG increment; the least significant bit
  46.      * is set to odd to ensure a full period LCG. The 2nd element is used
  47.      * to set the LCG state.</p>
  48.      */
  49.     AbstractL64(long[] seed) {
  50.         setState(extendSeed(seed, SEED_SIZE));
  51.     }

  52.     /**
  53.      * Creates a new instance using a 2 element seed.
  54.      *
  55.      * <p>The 1st element is used to set the LCG increment; the least significant bit
  56.      * is set to odd to ensure a full period LCG. The 2nd element is used
  57.      * to set the LCG state.</p>
  58.      *
  59.      * @param seed0 Initial seed element 0.
  60.      * @param seed1 Initial seed element 1.
  61.      */
  62.     AbstractL64(long seed0, long seed1) {
  63.         // Additive parameter must be odd
  64.         la = seed0 | 1;
  65.         ls = seed1;
  66.     }

  67.     /**
  68.      * Creates a copy instance.
  69.      *
  70.      * @param source Source to copy.
  71.      */
  72.     AbstractL64(AbstractL64 source) {
  73.         super(source);
  74.         la = source.la;
  75.         ls = source.ls;
  76.     }

  77.     /**
  78.      * Copies the state into the generator state.
  79.      *
  80.      * @param state the new state
  81.      */
  82.     private void setState(long[] state) {
  83.         // Additive parameter must be odd
  84.         la = state[0] | 1;
  85.         ls = state[1];
  86.     }

  87.     /** {@inheritDoc} */
  88.     @Override
  89.     protected byte[] getStateInternal() {
  90.         return composeStateInternal(NumberFactory.makeByteArray(
  91.                                         new long[] {la, ls}),
  92.                                     super.getStateInternal());
  93.     }

  94.     /** {@inheritDoc} */
  95.     @Override
  96.     protected void setStateInternal(byte[] s) {
  97.         final byte[][] c = splitStateInternal(s, SEED_SIZE * Long.BYTES);
  98.         setState(NumberFactory.makeLongArray(c[0]));
  99.         super.setStateInternal(c[1]);
  100.     }

  101.     /**
  102.      * Creates a copy of the UniformRandomProvider and then <em>retreats</em> the state of the
  103.      * current instance. The copy is returned.
  104.      *
  105.      * <p>The jump is performed by advancing the state of the LCG sub-generator by 1 cycle.
  106.      * The XBG state is unchanged.
  107.      */
  108.     @Override
  109.     public UniformRandomProvider jump() {
  110.         final UniformRandomProvider copy = copy();
  111.         // Advance the LCG 1 step
  112.         ls = LXMSupport.M64 * ls + la;
  113.         resetCachedState();
  114.         return copy;
  115.     }

  116.     /**
  117.      * Creates a copy of the UniformRandomProvider and then <em>retreats</em> the state of the
  118.      * current instance. The copy is returned.
  119.      *
  120.      * <p>The jump is performed by advancing the state of the LCG sub-generator by
  121.      * 2<sup>32</sup> cycles. The XBG state is unchanged.
  122.      */
  123.     @Override
  124.     public JumpableUniformRandomProvider longJump() {
  125.         final JumpableUniformRandomProvider copy = copy();
  126.         // Advance the LCG 2^32 steps
  127.         ls = LXMSupport.M64P * ls + LXMSupport.C64P * la;
  128.         resetCachedState();
  129.         return copy;
  130.     }

  131.     /**
  132.      * Create a copy.
  133.      *
  134.      * @return the copy
  135.      */
  136.     abstract AbstractL64 copy();
  137. }