XorShift1024Star.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 java.util.Arrays;

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

  22. /**
  23.  * A fast RNG implementing the {@code XorShift1024*} algorithm.
  24.  *
  25.  * <p>Note: This has been superseded by {@link XorShift1024StarPhi}. The sequences emitted
  26.  * by both generators are correlated.</p>
  27.  *
  28.  * @see <a href="http://xorshift.di.unimi.it/xorshift1024star.c">Original source code</a>
  29.  * @see <a href="https://en.wikipedia.org/wiki/Xorshift">Xorshift (Wikipedia)</a>
  30.  * @since 1.0
  31.  */
  32. public class XorShift1024Star extends LongProvider implements JumpableUniformRandomProvider {
  33.     /** Size of the state vector. */
  34.     private static final int SEED_SIZE = 16;
  35.     /** The coefficients for the jump function. */
  36.     private static final long[] JUMP_COEFFICIENTS = {
  37.         0x84242f96eca9c41dL, 0xa3c65b8776f96855L, 0x5b34a39f070b5837L, 0x4489affce4f31a1eL,
  38.         0x2ffeeb0a48316f40L, 0xdc2d9891fe68c022L, 0x3659132bb12fea70L, 0xaac17d8efa43cab8L,
  39.         0xc4cb815590989b13L, 0x5ee975283d71c93bL, 0x691548c86c1bd540L, 0x7910c41d10a1e6a5L,
  40.         0x0b5fc64563b3e2a8L, 0x047f7684e9fc949dL, 0xb99181f2d8f685caL, 0x284600e3f30e38c3L
  41.     };
  42.     /** State. */
  43.     private final long[] state = new long[SEED_SIZE];
  44.     /** The multiplier for the XorShift1024 algorithm. */
  45.     private final long multiplier;
  46.     /** Index in "state" array. */
  47.     private int index;

  48.     /**
  49.      * Creates a new instance.
  50.      *
  51.      * @param seed Initial seed.
  52.      * If the length is larger than 16, only the first 16 elements will
  53.      * be used; if smaller, the remaining elements will be automatically
  54.      * set. A seed containing all zeros will create a non-functional generator.
  55.      */
  56.     public XorShift1024Star(long[] seed) {
  57.         this(seed, 1181783497276652981L);
  58.     }

  59.     /**
  60.      * Creates a new instance.
  61.      *
  62.      * @param seed Initial seed.
  63.      * If the length is larger than 16, only the first 16 elements will
  64.      * be used; if smaller, the remaining elements will be automatically
  65.      * set. A seed containing all zeros will create a non-functional generator.
  66.      * @param multiplier The multiplier for the XorShift1024 algorithm.
  67.      * @since 1.3
  68.      */
  69.     protected XorShift1024Star(long[] seed, long multiplier) {
  70.         setSeedInternal(seed);
  71.         this.multiplier = multiplier;
  72.     }

  73.     /**
  74.      * Creates a copy instance.
  75.      *
  76.      * @param source Source to copy.
  77.      * @since 1.3
  78.      */
  79.     protected XorShift1024Star(XorShift1024Star source) {
  80.         super(source);
  81.         System.arraycopy(source.state, 0, state, 0, SEED_SIZE);
  82.         multiplier = source.multiplier;
  83.         index = source.index;
  84.     }

  85.     /** {@inheritDoc} */
  86.     @Override
  87.     protected byte[] getStateInternal() {
  88.         final long[] s = Arrays.copyOf(state, SEED_SIZE + 1);
  89.         s[SEED_SIZE] = index;

  90.         return composeStateInternal(NumberFactory.makeByteArray(s),
  91.                                     super.getStateInternal());
  92.     }

  93.     /** {@inheritDoc} */
  94.     @Override
  95.     protected void setStateInternal(byte[] s) {
  96.         final byte[][] c = splitStateInternal(s, (SEED_SIZE + 1) * 8);

  97.         final long[] tmp = NumberFactory.makeLongArray(c[0]);
  98.         System.arraycopy(tmp, 0, state, 0, SEED_SIZE);
  99.         index = (int) tmp[SEED_SIZE];

  100.         super.setStateInternal(c[1]);
  101.     }

  102.     /**
  103.      * Seeds the RNG.
  104.      *
  105.      * @param seed Seed.
  106.      */
  107.     private void setSeedInternal(long[] seed) {
  108.         // Reset the whole state of this RNG (i.e. "state" and "index").
  109.         // Filling procedure is not part of the reference code.
  110.         fillState(state, seed);
  111.         index = 0;
  112.     }

  113.     /** {@inheritDoc} */
  114.     @Override
  115.     public long next() {
  116.         final long s0 = state[index];
  117.         index = (index + 1) & 15;
  118.         long s1 = state[index];
  119.         s1 ^= s1 << 31; // a
  120.         state[index] = s1 ^ s0 ^ (s1 >>> 11) ^ (s0 >>> 30); // b,c
  121.         return state[index] * multiplier;
  122.     }

  123.     /**
  124.      * {@inheritDoc}
  125.      *
  126.      * <p>The jump size is the equivalent of 2<sup>512</sup>
  127.      * calls to {@link UniformRandomProvider#nextLong() nextLong()}. It can provide
  128.      * up to 2<sup>512</sup> non-overlapping subsequences.</p>
  129.      *
  130.      * @since 1.3
  131.      */
  132.     @Override
  133.     public UniformRandomProvider jump() {
  134.         final UniformRandomProvider copy = copy();
  135.         performJump();
  136.         return copy;
  137.     }

  138.     /**
  139.      * Create a copy.
  140.      *
  141.      * @return the copy
  142.      * @since 1.3
  143.      */
  144.     protected XorShift1024Star copy() {
  145.         // This exists to ensure the jump function returns
  146.         // the correct class type. It should not be public.
  147.         return new XorShift1024Star(this);
  148.     }

  149.     /**
  150.      * Perform the jump to advance the generator state. Resets the cached state of the generator.
  151.      */
  152.     private void performJump() {
  153.         final long[] newState = new long[SEED_SIZE];
  154.         for (final long jc : JUMP_COEFFICIENTS) {
  155.             for (int b = 0; b < 64; b++) {
  156.                 if ((jc & (1L << b)) != 0) {
  157.                     for (int i = 0; i < SEED_SIZE; i++) {
  158.                         newState[i] ^= state[(i + index) & 15];
  159.                     }
  160.                 }
  161.                 next();
  162.             }
  163.         }
  164.         for (int j = 0; j < 16; j++) {
  165.             state[(j + index) & 15] = newState[j];
  166.         }
  167.         resetCachedState();
  168.     }
  169. }