Exemple #1
0
        public IntegerNumber ModPow(IntegerNumber power, IntegerNumber prime, Func <IntegerNumber, IntegerNumber> modPFunction)
        {
            IntegerNumber a = this;

            if (power.IsNegative)
            {
                a     = a.ModInverse(prime);
                power = -power;
            }
            int highestBitPosition = power.Digits * 64 - 1;

            while (highestBitPosition >= 0 && !power.GetBitAt(highestBitPosition))
            {
                highestBitPosition--;
            }
            IntegerNumber result = highestBitPosition < 0 ? One : a;

            for (int i = highestBitPosition; --i >= 0;)
            {
                result = modPFunction(result.Square());
                if (power.GetBitAt(i))
                {
                    result = modPFunction(result * a);
                }
            }
            var diff = result - prime;

            return(diff.IsNegative ? result : diff);
        }
Exemple #2
0
        //f[x_] := x^2 - y
        //FullSimplify[x - f[x] / D[f[x], x]] = (x + y / x) / 2  [Newton method]
        //FullSimplify[x - 2*f[x]*D[f[x], x]/(2*D[f[x], x]^2 - f[x]*D[f[x], {x, 2}])] = x * (x^2 + 3 y) / (3 x^2 + y) [Halley]
        //In practice Newton method is faster than Halley 3'rd order convergence for SQRT.
        public IntegerNumber Sqrt()
        {
            if (this.IsNegative)
            {
                throw new ArithmeticException("NaN");
            }
            if (this.IsZero)
            {
                return(IntegerNumber.Zero);
            }
            shrink(this);
            int n = this.Digits;
            int computedDigits = (n & 1) != 0 ? 1 : 2;

            if (computedDigits + 2 <= n)
            {
                computedDigits += 2;
            }

            ulong[]       inputBits  = this.bits;
            IntegerNumber t          = this.GetDigits(n - computedDigits, computedDigits, true);
            double        estimate   = Math.Sqrt(t.ToDouble);
            double        highDouble = Math.Floor(estimate / Power2_64);
            double        lowDouble  = estimate - highDouble * Power2_64;
            IntegerNumber root       = new IntegerNumber(new ulong[] { (ulong)lowDouble, (ulong)highDouble }, false);

            if (root.IsNegative)
            {
                Array.Resize(ref root.bits, 3);
            }
            while (true)
            {
                IntegerNumber oldRoot = root;
                root = (root + t / root) >> 1;
                if (IntegerNumber.Abs(oldRoot - root) <= IntegerNumber.One)
                {
                    break;
                }
            }
            int additionalDigits = 1;

            for (int i = computedDigits; i < n + additionalDigits;)
            {
                int digits = Math.Min(computedDigits, n - computedDigits + 1) >> 1;
                i              += computedDigits;
                root          <<= digits * 64;
                computedDigits += digits * 2;
                t               = computedDigits >= n ? this : this.GetDigits(n - computedDigits, computedDigits, true);
                root            = (root + t / root) >> 1;
            }
            IntegerNumber square = root.Square();

            return(this >= square ? root : root - IntegerNumber.One);
        }
Exemple #3
0
        public static IntegerNumber Pow(int baseNumber, int exponent)
        {
            int highestBitPosition = BSR((uint)exponent);

            if (highestBitPosition < 0)
            {
                return(IntegerNumber.One);
            }
            IntegerNumber number = new IntegerNumber(baseNumber);
            IntegerNumber result = number;

            for (int i = highestBitPosition; --i >= 0;)
            {
                result = result.Square();
                shrink(result);
                if ((exponent & (1 << i)) != 0)
                {
                    result *= baseNumber;
                }
            }
            return(result);
        }
Exemple #4
0
        //InverseSqrt[this] = Sqrt[(this << (this.Digits * 64)).Inverse()]
        //InverseSqrt[this] = Sqrt[(1 << (this.Digits * 192)) / this]
        //f[x_] := (1/x)^2 - y
        //FullSimplify[x - f[x] / D[f[x], x]] = x * (1/2) * (3 - x^2 y)
        public IntegerNumber InverseSqrt()
        {
            if (this.IsNegative || this.IsZero)
            {
                throw new ArithmeticException("NaN");
            }
            shrink(this);
            int n = this.Digits;
            int computedDigits = (n & 1) != 0 ? 1 : 2;

            if (computedDigits + 2 <= n)
            {
                computedDigits += 2;
            }

            ulong[]       inputBits     = this.bits;
            IntegerNumber t             = this.GetDigits(n - computedDigits, computedDigits, true);
            double        estimate      = Math.Pow(Power2_64, computedDigits * 1.5) / Math.Sqrt(t.ToDouble);
            List <ulong>  initialDigits = new List <ulong>();

            while (estimate != 0)
            {
                initialDigits.Add((ulong)Math.IEEERemainder(estimate, Power2_64));
                estimate = Math.Floor(estimate / Power2_64);
            }
            IntegerNumber root  = new IntegerNumber(initialDigits.ToArray(), false);
            IntegerNumber three = new IntegerNumber(3L);
            //repeat iteration once to reach full precision.
            int iterations1 = (int)Math.Ceiling(Math.Log(initialDigits.Count * 64.0 / 52, 2.0));

            for (int step = iterations1; --step >= 0;)
            {
                int shift = computedDigits * 64 * 3;
                root = root * ((three << shift) - root.Square() * t) >> (1 + shift);
                shrink(root);
            }
            if (computedDigits == n)
            {
                return(root);
            }

            int additionalDigits = 2;
            int totalDigits      = n + additionalDigits;

            do
            {
                int digits = Math.Min(Math.Max(computedDigits - 1, 1), totalDigits - computedDigits);
                computedDigits += digits;
                t = this.GetDigits(n - computedDigits, computedDigits, true);

                //root <<= digits * 64;
                //int shift = computedDigits * 3 * 64;
                //root = root * ((three << shift) - root.Square() * t) >> (1 + shift);

                int shift1 = (computedDigits * 3 - digits * 2) * 64;
                int shift2 = (computedDigits * 3 - digits * 3) * 64;
                root = root * ((three << shift1) - root.Square() * t) >> (1 + shift2);

                shrink(root);
            } while (computedDigits < totalDigits);

            root >>= additionalDigits * 64;
            shrink(root);

            return(root);
        }