private static void SeekStateInternal(ref uint state0, ref uint state1, ulong offset, bool reverse) { if (offset >= _MaximumPeriod) { offset %= _MaximumPeriod; } if (offset == 0) { return; } { MyUInt256 aexpn = new MyUInt256(reverse ? _Multiplier0Inverse : _Multiplier0); aexpn.ExpMod(offset, new MyUInt256(_Modulus)); state0 = unchecked ((uint)((aexpn.ToUInt64() * state0) % _Modulus)); } { MyUInt256 aexpn = new MyUInt256(reverse ? _Multiplier1Inverse : _Multiplier1); aexpn.ExpMod(offset, new MyUInt256(_Modulus1)); state1 = unchecked ((uint)((aexpn.ToUInt64() * state1) % _Modulus1)); } }
/// <summary> /// Computes the state at the specified position in the pseudorandom stream relative to a given initial state. /// </summary> /// <param name="state">The state at position zero in the stream.</param> /// <param name="offset">The number of states to skip.</param> /// <param name="multiplier">The linear congruential generator's multiplier constant, or its multiplicative inverse modulo <paramref name="divisor"/> to go backwards.</param> /// <param name="increment">The linear congruential generator's increment constant, /// or its additive inverse modulo <paramref name="divisor"/> multiplied by the multiplicative inverse to go backwards.</param> /// <param name="divisor">The linear congruential generator's modulus constant.</param> /// <returns>The state at position <paramref name="offset"/> in the stream.</returns> protected static ulong SeekState(ulong state, ulong offset, ulong multiplier, ulong increment, ulong divisor) { // NewState = (Multiplier**Offset * OldState) + Increment * (Multiplier**Offset - 1) / (Multiplier - 1) // caller can substitute Multiplier**-1 and -Increment * Multiplier**-1 to go backwards if (offset == 0) { return(state); } if (multiplier == 0) { return(increment); } else if (multiplier == 1) { MyUInt256 product = new MyUInt256(increment); product.Multiply(offset); if (divisor != 0) { product.Modulo(divisor); } return(product.ToUInt64()); } MyUInt256 compdivisor = new MyUInt256(divisor); if (divisor == 0) { compdivisor.Set(0, 1); } compdivisor.Multiply(multiplier - 1); MyUInt256 aexpn = new MyUInt256(multiplier); aexpn.ExpMod(offset, compdivisor); // = Multiplier**Offset MyUInt256 fraction = new MyUInt256(aexpn); fraction.Subtract(1); fraction.Divide(multiplier - 1); // should always divide evenly; that's why divisor has to include (Multiplier - 1) factor though fraction.Multiply(increment); // = Increment * (Multiplier**Offset - 1) / (Multiplier - 1) MyUInt256 newstate = new MyUInt256(state); newstate.Multiply(aexpn); // = Multiplier**Offset * OldState newstate.Add(fraction); // = (Multiplier**Offset * OldState) + Increment * (Multiplier**Offset - 1) / (Multiplier - 1) if (divisor != 0) { newstate.Modulo(divisor); // now that we've divided by (Multiplier - 1), we can go back to using 'divisor' instead of 'compdivisor' } return(newstate.ToUInt64()); } //PrngLcgBase.SeekState
protected static ulong GetMultiplicativeInverse(ulong multiplier, ulong divisor) { ulong mi; if (multiplier >= divisor && divisor != 0) { return(0); } if (unchecked ((long)multiplier) < 0 || unchecked ((long)divisor) <= 0) { mi = ModularMath.MultiplicativeInverse(unchecked ((long)multiplier), unchecked ((long)divisor)); } else { MyUInt256 mibig = ModularMath.MultiplicativeInverse(new MyUInt256(multiplier), (divisor == 0 ? new MyUInt256(0, 1) : new MyUInt256(divisor))); mi = (mibig == null ? 0 : mibig.ToUInt64()); } return(mi); } //PrngLcgBase.GetMultiplicativeInverse
public override void SeekBack(ulong offset) { if (offset == 0) { return; } ulong multiplier = this.Multiplier; ulong increment = this.Increment; ulong divisor = this.Modulus; ulong mi = GetMultiplicativeInverse(multiplier, divisor); if (mi == 0) { // guessing that modulus is a multiple of period, in which case seeking ahead (modulus - offset) states will reverse by 'offset' states SeekAhead(unchecked (divisor - offset)); return; } if (increment >= divisor && divisor != 0) { increment %= divisor; } if (increment != 0) { MyUInt256 incrinverse = new MyUInt256(unchecked (divisor - increment)); // negate increment (modulo divisor) to get additive inverse incrinverse.Multiply(mi); if (divisor != 0) { incrinverse.Modulo(divisor); } increment = incrinverse.ToUInt64(); } this._LcgState = SeekState(this._LcgState, offset, mi, increment, divisor); } //PrngLcgBase.SeekBack
/// <summary> /// Performs discard, modulus, and/or take-from-top transformations on a raw value to produce output according to the PRNG's parameters. /// </summary> /// <param name="raw">The raw bits to transform.</param> /// <param name="limit">The lowest positive integer greater than the maximum desired value.</param> /// <returns>A value suitable for output.</returns> protected virtual ulong ValueFromRaw(ulong raw, ulong limit) { if (this.DiscardDivisor != 0) { raw /= this.DiscardDivisor; if (this.OutputDivisor != 0) { raw %= this.OutputDivisor; } return(raw); } else { // TO-DO TODO: should we incorporate OutputDivisor somehow? MyUInt256 product = new MyUInt256(raw); product.Multiply(limit); product.Divide(this.Modulus); return(product.ToUInt64()); } }
/// <summary> /// Computes the state at the specified position in the pseudorandom stream relative to a given initial state. /// </summary> /// <param name="state">The state at position zero in the stream.</param> /// <param name="offset">The number of states to skip.</param> /// <param name="multiplier">The linear congruential generator's multiplier constant, or its multiplicative inverse modulo <paramref name="divisor"/> to go backwards.</param> /// <param name="divisor">The linear congruential generator's modulus constant.</param> /// <returns>The state at position <paramref name="offset"/> in the stream.</returns> protected static ulong SeekState(ulong state, ulong offset, ulong multiplier, ulong divisor) { // NewState = (Multiplier**Offset * OldState) // caller can substitute Multiplier**-1 to go backwards if (offset == 0) { return(state); } MyUInt256 fullmodulus = (divisor == 0 ? new MyUInt256(0, 1) : new MyUInt256(divisor)); MyUInt256 aexpn = new MyUInt256(multiplier); aexpn.ExpMod(offset, fullmodulus); aexpn.Multiply(state); if (divisor != 0) { aexpn.Modulo(fullmodulus); } return(aexpn.ToUInt64()); } //PrngLehmerBase.SeekState
private static void SeekStateInternal(ref uint state0, ref uint state1, ulong offset, bool reverse) { if (offset >= _MaximumPeriod) offset %= _MaximumPeriod; if (offset == 0) return; { MyUInt256 aexpn = new MyUInt256(reverse ? _Multiplier0Inverse : _Multiplier0); aexpn.ExpMod(offset, new MyUInt256(_Modulus)); state0 = unchecked((uint)((aexpn.ToUInt64() * state0) % _Modulus)); } { MyUInt256 aexpn = new MyUInt256(reverse ? _Multiplier1Inverse : _Multiplier1); aexpn.ExpMod(offset, new MyUInt256(_Modulus1)); state1 = unchecked((uint)((aexpn.ToUInt64() * state1) % _Modulus1)); } }
/// <summary> /// Computes the state at the specified position in the pseudorandom stream relative to a given initial state. /// </summary> /// <param name="state">The state at position zero in the stream.</param> /// <param name="offset">The number of states to skip.</param> /// <param name="multiplier">The linear congruential generator's multiplier constant, or its multiplicative inverse modulo <paramref name="divisor"/> to go backwards.</param> /// <param name="divisor">The linear congruential generator's modulus constant.</param> /// <returns>The state at position <paramref name="offset"/> in the stream.</returns> protected static ulong SeekState(ulong state, ulong offset, ulong multiplier, ulong divisor) { // NewState = (Multiplier**Offset * OldState) // caller can substitute Multiplier**-1 to go backwards if (offset == 0) return state; MyUInt256 fullmodulus = (divisor == 0 ? new MyUInt256(0, 1) : new MyUInt256(divisor)); MyUInt256 aexpn = new MyUInt256(multiplier); aexpn.ExpMod(offset, fullmodulus); aexpn.Multiply(state); if (divisor != 0) aexpn.Modulo(fullmodulus); return aexpn.ToUInt64(); }
/// <summary> /// Performs discard, modulus, and/or take-from-top transformations on a raw value to produce output according to the PRNG's parameters. /// </summary> /// <param name="raw">The raw bits to transform.</param> /// <param name="limit">The lowest positive integer greater than the maximum desired value.</param> /// <returns>A value suitable for output.</returns> protected virtual ulong ValueFromRaw(ulong raw, ulong limit) { if (this.DiscardDivisor != 0) { raw /= this.DiscardDivisor; if (this.OutputDivisor != 0) raw %= this.OutputDivisor; return raw; } else { // TO-DO TODO: should we incorporate OutputDivisor somehow? MyUInt256 product = new MyUInt256(raw); product.Multiply(limit); product.Divide(this.Modulus); return (product.ToUInt64()); } }
/// <summary> /// Computes the state at the specified position in the pseudorandom stream relative to a given initial state. /// </summary> /// <param name="state">The state at position zero in the stream.</param> /// <param name="offset">The number of states to skip.</param> /// <param name="multiplier">The linear congruential generator's multiplier constant, or its multiplicative inverse modulo <paramref name="divisor"/> to go backwards.</param> /// <param name="increment">The linear congruential generator's increment constant, /// or its additive inverse modulo <paramref name="divisor"/> multiplied by the multiplicative inverse to go backwards.</param> /// <param name="divisor">The linear congruential generator's modulus constant.</param> /// <returns>The state at position <paramref name="offset"/> in the stream.</returns> protected static ulong SeekState(ulong state, ulong offset, ulong multiplier, ulong increment, ulong divisor) { // NewState = (Multiplier**Offset * OldState) + Increment * (Multiplier**Offset - 1) / (Multiplier - 1) // caller can substitute Multiplier**-1 and -Increment * Multiplier**-1 to go backwards if (offset == 0) return state; if (multiplier == 0) { return increment; } else if (multiplier == 1) { MyUInt256 product = new MyUInt256(increment); product.Multiply(offset); if (divisor != 0) product.Modulo(divisor); return product.ToUInt64(); } MyUInt256 compdivisor = new MyUInt256(divisor); if (divisor == 0) compdivisor.Set(0, 1); compdivisor.Multiply(multiplier - 1); MyUInt256 aexpn = new MyUInt256(multiplier); aexpn.ExpMod(offset, compdivisor); // = Multiplier**Offset MyUInt256 fraction = new MyUInt256(aexpn); fraction.Subtract(1); fraction.Divide(multiplier - 1); // should always divide evenly; that's why divisor has to include (Multiplier - 1) factor though fraction.Multiply(increment); // = Increment * (Multiplier**Offset - 1) / (Multiplier - 1) MyUInt256 newstate = new MyUInt256(state); newstate.Multiply(aexpn); // = Multiplier**Offset * OldState newstate.Add(fraction); // = (Multiplier**Offset * OldState) + Increment * (Multiplier**Offset - 1) / (Multiplier - 1) if (divisor != 0) newstate.Modulo(divisor); // now that we've divided by (Multiplier - 1), we can go back to using 'divisor' instead of 'compdivisor' return newstate.ToUInt64(); }
public override ulong SeekSeedBack(ulong seed, ulong offset) { if (offset == 0) return seed; ulong multiplier = this.Multiplier; ulong increment = this.Increment; ulong divisor = this.Modulus; ulong mi = GetMultiplicativeInverse(multiplier, divisor); if (mi == 0) { // guessing that modulus is a multiple of period, in which case seeking ahead (modulus - offset) states will reverse by 'offset' states return SeekSeedAhead(seed, unchecked(divisor - offset)); } if (increment >= divisor && divisor != 0) increment %= divisor; if (increment != 0) { MyUInt256 incrinverse = new MyUInt256(unchecked(divisor - increment)); // negate increment (modulo divisor) to get additive inverse incrinverse.Multiply(mi); if (divisor != 0) incrinverse.Modulo(divisor); increment = incrinverse.ToUInt64(); } return SeekState(this._LcgState, offset, mi, increment, divisor); }