AbstractL128.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 128-bit LCG sub-generator. The class implements
  25.  * the jump functions.
  26.  *
  27.  * @since 1.5
  28.  */
  29. abstract class AbstractL128 extends LongProvider implements LongJumpableUniformRandomProvider {
  30.     /** Size of the seed vector. */
  31.     private static final int SEED_SIZE = 4;
  32.     /** Low half of 128-bit LCG multiplier. */
  33.     private static final long ML = LXMSupport.M128L;

  34.     /** High half of the 128-bit per-instance LCG additive parameter.
  35.      * Cannot be final to support RestorableUniformRandomProvider. */
  36.     protected long lah;
  37.     /** Low half of the 128-bit per-instance LCG additive parameter (must be odd).
  38.      * Cannot be final to support RestorableUniformRandomProvider. */
  39.     protected long lal;
  40.     /** High half of the 128-bit state of the LCG generator. */
  41.     protected long lsh;
  42.     /** Low half of the 128-bit state of the LCG generator. */
  43.     protected long lsl;

  44.     /**
  45.      * Creates a new instance.
  46.      *
  47.      * @param seed Initial seed.
  48.      * If the length is larger than 4, only the first 4 elements will
  49.      * be used; if smaller, the remaining elements will be automatically
  50.      * set.
  51.      *
  52.      * <p>The 1st and 2nd elements are used to set the LCG increment; the least significant bit
  53.      * is set to odd to ensure a full period LCG. The 3rd and 4th elements are used
  54.      * to set the LCG state.</p>
  55.      */
  56.     AbstractL128(long[] seed) {
  57.         setState(extendSeed(seed, SEED_SIZE));
  58.     }

  59.     /**
  60.      * Creates a new instance using a 4 element seed.
  61.      *
  62.      * <p>The 1st and 2nd elements are used to set the LCG increment; the least significant bit
  63.      * is set to odd to ensure a full period LCG. The 3rd and 4th elements are used
  64.      * to set the LCG state.</p>
  65.      *
  66.      * @param seed0 Initial seed element 0.
  67.      * @param seed1 Initial seed element 1.
  68.      * @param seed2 Initial seed element 2.
  69.      * @param seed3 Initial seed element 3.
  70.      */
  71.     AbstractL128(long seed0, long seed1, long seed2, long seed3) {
  72.         lah = seed0;
  73.         // Additive parameter must be odd
  74.         lal = seed1 | 1;
  75.         lsh = seed2;
  76.         lsl = seed3;
  77.     }

  78.     /**
  79.      * Creates a copy instance.
  80.      *
  81.      * @param source Source to copy.
  82.      */
  83.     AbstractL128(AbstractL128 source) {
  84.         super(source);
  85.         lah = source.lah;
  86.         lal = source.lal;
  87.         lsh = source.lsh;
  88.         lsl = source.lsl;
  89.     }

  90.     /**
  91.      * Copies the state into the generator state.
  92.      *
  93.      * @param state the new state
  94.      */
  95.     private void setState(long[] state) {
  96.         lah = state[0];
  97.         // Additive parameter must be odd
  98.         lal = state[1] | 1;
  99.         lsh = state[2];
  100.         lsl = state[3];
  101.     }

  102.     /** {@inheritDoc} */
  103.     @Override
  104.     protected byte[] getStateInternal() {
  105.         return composeStateInternal(NumberFactory.makeByteArray(
  106.                                         new long[] {lah, lal, lsh, lsl}),
  107.                                     super.getStateInternal());
  108.     }

  109.     /** {@inheritDoc} */
  110.     @Override
  111.     protected void setStateInternal(byte[] s) {
  112.         final byte[][] c = splitStateInternal(s, SEED_SIZE * Long.BYTES);
  113.         setState(NumberFactory.makeLongArray(c[0]));
  114.         super.setStateInternal(c[1]);
  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 1 cycle.
  121.      * The XBG state is unchanged.
  122.      */
  123.     @Override
  124.     public UniformRandomProvider jump() {
  125.         final UniformRandomProvider copy = copy();
  126.         // Advance the LCG 1 step.
  127.         // The LCG is, in effect, "s = m * s + a" where m = ((1LL << 64) + ML)
  128.         final long sh = lsh;
  129.         final long sl = lsl;
  130.         final long u = ML * sl;
  131.         // High half
  132.         lsh = ML * sh + LXMSupport.unsignedMultiplyHigh(ML, sl) + sl + lah +
  133.               // Carry propagation
  134.               LXMSupport.unsignedAddHigh(u, lal);
  135.         // Low half
  136.         lsl = u + lal;
  137.         resetCachedState();
  138.         return copy;
  139.     }

  140.     /**
  141.      * Creates a copy of the UniformRandomProvider and then <em>retreats</em> the state of the
  142.      * current instance. The copy is returned.
  143.      *
  144.      * <p>The jump is performed by advancing the state of the LCG sub-generator by
  145.      * 2<sup>64</sup> cycles. The XBG state is unchanged.
  146.      */
  147.     @Override
  148.     public JumpableUniformRandomProvider longJump() {
  149.         final JumpableUniformRandomProvider copy = copy();
  150.         // Advance the LCG 2^64 steps
  151.         // s = m' * s + c' * c
  152.         // Specialised routine given M128PL=1, C128PL=0 and many terms
  153.         // can be dropped as the low half is unchanged and there is no carry
  154.         // sh = m'l * sh         // sh
  155.         //    + high(m'l * sl)   // dropped as m'l=1 and there is no high part
  156.         //    + m'h * sl
  157.         //    + c'l * ah         // dropped as c'l=0
  158.         //    + high(c'l * ah)   // dropped as c'l=0
  159.         //    + c'h * al
  160.         // sl = m'l * sl + c'l * al
  161.         //    = sl
  162.         lsh = lsh + LXMSupport.M128PH * lsl + LXMSupport.C128PH * lal;
  163.         resetCachedState();
  164.         return copy;
  165.     }

  166.     /**
  167.      * Create a copy.
  168.      *
  169.      * @return the copy
  170.      */
  171.     abstract AbstractL128 copy();
  172. }