/// <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
} //ModularMath.ExtendedEuclidean(long,long,out ulong) /// <summary> /// Computes the greatest common divisor (GCD) of <paramref name="a"/> and <paramref name="b"/>, /// as well as the multiplicative inverse of <paramref name="a"/> modulo <paramref name="b"/>. /// </summary> /// <param name="a">A positive integer less than <paramref name="b"/>.</param> /// <param name="b">A positive integer greater than <paramref name="a"/>.</param> /// <param name="mulInverse">Receives the multiplicative inverse of <paramref name="a"/> modulo <paramref name="b"/> /// if <paramref name="a"/> and <paramref name="b"/> are coprime, or null otherwise.</param> /// <returns>The greatest common divisor of <paramref name="a"/> and <paramref name="b"/>.</returns> public static MyUInt256 ExtendedEuclidean(MyUInt256 a, MyUInt256 b, out MyUInt256 mulInverse) { if (a.IsZero() || a.Compare(b) >= 0) { throw new ArgumentOutOfRangeException("a must be a positive integer less than b"); } MyUInt256 r0 = new MyUInt256(b), r1 = new MyUInt256(a); // ordered this way because b > a MyUInt256 q = new MyUInt256(), r = new MyUInt256(); MyUInt256 x0 = new MyUInt256(0), x1 = new MyUInt256(1); // x is a's coefficient; we don't maintain b's coefficient MyUInt256 x = new MyUInt256(1); // return multiplicative inverse of 1 if loop breaks before x is assigned and if GCD (q) is 1 MyUInt256 tmp = new MyUInt256(); for (; ;) { r.Set(r0); // r = r0 % r1 r.Modulo(r1); if (r.IsZero()) { break; // break before overwriting previous value of q } q.Set(r0); // q = r0 / r1 q.Divide(r1); x.Set(x0); // x = x0 - q * x1 tmp.Set(q); tmp.Multiply(x1); x.Subtract(tmp); r0.Set(r1); r1.Set(r); x0.Set(x1); x1.Set(x); } if (x.IsMsbSet()) { x.Add(b); } mulInverse = (r1.Compare(1) == 0 ? x : null); return(r1); } //ModularMath.ExtendedEuclidean(MyUInt256,MyUInt256,out MyUInt256)
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> /// 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
/// <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> /// 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); }
/// <summary> /// Computes the greatest common divisor (GCD) of <paramref name="a"/> and <paramref name="b"/>, /// as well as the multiplicative inverse of <paramref name="a"/> modulo <paramref name="b"/>. /// </summary> /// <param name="a">A positive integer less than <paramref name="b"/>.</param> /// <param name="b">A positive integer greater than <paramref name="a"/>.</param> /// <param name="mulInverse">Receives the multiplicative inverse of <paramref name="a"/> modulo <paramref name="b"/> /// if <paramref name="a"/> and <paramref name="b"/> are coprime, or null otherwise.</param> /// <returns>The greatest common divisor of <paramref name="a"/> and <paramref name="b"/>.</returns> public static MyUInt256 ExtendedEuclidean(MyUInt256 a, MyUInt256 b, out MyUInt256 mulInverse) { if (a.IsZero() || a.Compare(b) >= 0) throw new ArgumentOutOfRangeException("a must be a positive integer less than b"); MyUInt256 r0 = new MyUInt256(b), r1 = new MyUInt256(a); // ordered this way because b > a MyUInt256 q = new MyUInt256(), r = new MyUInt256(); MyUInt256 x0 = new MyUInt256(0), x1 = new MyUInt256(1); // x is a's coefficient; we don't maintain b's coefficient MyUInt256 x = new MyUInt256(1); // return multiplicative inverse of 1 if loop breaks before x is assigned and if GCD (q) is 1 MyUInt256 tmp = new MyUInt256(); for (; ; ) { r.Set(r0); // r = r0 % r1 r.Modulo(r1); if (r.IsZero()) break; // break before overwriting previous value of q q.Set(r0); // q = r0 / r1 q.Divide(r1); x.Set(x0); // x = x0 - q * x1 tmp.Set(q); tmp.Multiply(x1); x.Subtract(tmp); r0.Set(r1); r1.Set(r); x0.Set(x1); x1.Set(x); } if (x.IsMsbSet()) x.Add(b); mulInverse = (r1.Compare(1) == 0 ? x : null); return r1; }