001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.rng.core.source32; 018 019import org.apache.commons.rng.core.util.NumberFactory; 020 021/** 022 * Port from Marsaglia's <a href="http://www.cse.yorku.ca/~oz/marsaglia-rng.html"> 023 * "KISS" algorithm</a>. 024 * This version contains the correction referred to 025 * <a href="https://programmingpraxis.com/2010/10/05/george-marsaglias-random-number-generators/">here</a> 026 * in a reply to the original post. 027 * 028 * @see <a href="https://en.wikipedia.org/wiki/KISS_(algorithm)">KISS (Wikipedia)</a> 029 * @since 1.0 030 */ 031public class KISSRandom extends IntProvider { 032 /** Size of the seed. */ 033 private static final int SEED_SIZE = 4; 034 /** State variable. */ 035 private int z; 036 /** State variable. */ 037 private int w; 038 /** State variable. */ 039 private int jsr; 040 /** State variable. */ 041 private int jcong; 042 043 /** 044 * Creates a new instance. 045 * 046 * @param seed Seed. 047 * If the length is larger than 4, only the first 4 elements will 048 * be used; if smaller, the remaining elements will be automatically 049 * set. 050 */ 051 public KISSRandom(int[] seed) { 052 setSeedInternal(seed); 053 } 054 055 /** {@inheritDoc} */ 056 @Override 057 protected byte[] getStateInternal() { 058 return composeStateInternal(NumberFactory.makeByteArray(new int[] {z, w, jsr, jcong}), 059 super.getStateInternal()); 060 } 061 062 /** {@inheritDoc} */ 063 @Override 064 protected void setStateInternal(byte[] s) { 065 final byte[][] c = splitStateInternal(s, SEED_SIZE * 4); 066 067 final int[] tmp = NumberFactory.makeIntArray(c[0]); 068 z = tmp[0]; 069 w = tmp[1]; 070 jsr = tmp[2]; 071 jcong = tmp[3]; 072 073 super.setStateInternal(c[1]); 074 } 075 076 /** 077 * Seeds the RNG. 078 * 079 * @param seed Seed. 080 */ 081 private void setSeedInternal(int[] seed) { 082 // Reset the whole state of this RNG (i.e. the 4 state variables). 083 // Filling procedure is not part of the reference code. 084 final int[] tmp = new int[SEED_SIZE]; 085 fillState(tmp, seed); 086 087 z = tmp[0]; 088 w = tmp[1]; 089 jsr = tmp[2]; 090 jcong = tmp[3]; 091 } 092 093 /** {@inheritDoc} */ 094 @Override 095 public int next() { 096 z = computeNew(36969, z); 097 w = computeNew(18000, w); 098 final int mwc = (z << 16) + w; 099 100 // Cf. correction mentioned in the reply to the original post: 101 // https://programmingpraxis.com/2010/10/05/george-marsaglias-random-number-generators/ 102 jsr ^= jsr << 13; 103 jsr ^= jsr >>> 17; 104 jsr ^= jsr << 5; 105 106 jcong = 69069 * jcong + 1234567; 107 108 return (mwc ^ jcong) + jsr; 109 } 110 111 /** 112 * Compute new value. 113 * 114 * @param mult Multiplier. 115 * @param previous Previous value. 116 * @return new value. 117 */ 118 private static int computeNew(int mult, 119 int previous) { 120 return mult * (previous & 65535) + (previous >>> 16); 121 } 122}