Beispiel #1
0
        /// <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
Beispiel #2
0
        } //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)
Beispiel #3
0
        /// <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());
            }
        }
Beispiel #4
0
        /// <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());
            }
        }
Beispiel #5
0
        /// <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();
        }
Beispiel #6
0
        /// <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;
        }