コード例 #1
0
        public static IntegerNumber Inverse(IntegerNumber number, out IntegerNumber remainder)
        {
            int n = number.Digits;

            if (n <= IntegerDigitsBreakPoint)
            {
                ulong[] a = new ulong[(n + 1) * 2];
                a[n * 2] = 1UL;
                IntegerNumber b = number.ExtendTo(n + 1);
                ulong[]       q = new ulong[(n + 1) * 2];
                AsmX64Operations.GetDivMod(a, b.bits, n + 1, q, true);
                remainder = new IntegerNumber(a, false);
                shrink(remainder);
                IntegerNumber result = new IntegerNumber(q, false);
                shrink(result);
                return(result);
            }

            bool isNegative = false;

            if (number.IsNegative)
            {
                number     = -number;
                isNegative = true;
                n          = number.Digits;
            }
            //Newton iteration: x <- x + x * (1 - d * x^2)
            int           m = (n + 5) >> 1;
            IntegerNumber dx, dhi = number.GetDigits(n - m, m, false);
            IntegerNumber x = Inverse(dhi, out dx);

            //IntegerNumber test = x * d + dx;
            //shrink(ref test);
            //if (test.Digits != d.Digits * 2 + 1 || test.bits[d.Digits * 2] != 1UL || Enumerable.Range(0, d.Digits * 2).Any(idx => test.bits[idx] != 0UL))
            //{
            //    System.Diagnostics.Debugger.Break();
            //}

            const int     CorrectionDigits = 4;
            IntegerNumber dlo = number.GetDigits(0, n - m, true);

            IntegerNumber dp    = (dx << ((n - m) * 64)) - dlo * x;
            IntegerNumber delta = dp >> ((m - CorrectionDigits) * 64);  //keep one additional correction digit.

            shrink(delta);

            delta  *= x;
            delta >>= (m + CorrectionDigits) * 64;
            shrink(delta);

            x <<= (n - m) * 64;
            x  += delta;

            //FACT: number * x == (IntegerNumber.One << (n * 128)) - ((dp << ((n - m) * 64)) - delta * number);
            //but :     remainder = number * x;
            //then:     Array.Resize(ref remainder.bits, n * 2);
            //then:     shrink(ref remainder);
            //then:     remainder = -remainder;
            remainder = ((dp - delta * dhi) << ((n - m) * 64)) - delta * dlo;
            shrink(remainder);

            int count = 0;

            while (remainder.IsNegative)
            {
                remainder += number;
                x         -= One;
                count++;
                if (count >= 2)
                {
                    System.Diagnostics.Debugger.Break();
                }
            }
            while (remainder >= number)
            {
                remainder -= number;
                x         += One;
                count++;
                if (count >= 2)
                {
                    System.Diagnostics.Debugger.Break();
                }
            }

            if (isNegative)
            {
                x         = -x;
                remainder = -remainder;
            }
            return(x);
        }
コード例 #2
0
        public static IntegerNumber DivRem(IntegerNumber dividend, IntegerNumber divisor, out IntegerNumber remainder)
        {
            shrink(dividend);
            shrink(divisor);
            int           dividendDigits = dividend.Digits;
            int           divisorDigits  = divisor.Digits;
            IntegerNumber quotient;
            int           n = Math.Max(divisorDigits, (dividendDigits + 1) >> 1);

            if (divisorDigits <= IntegerDigitsBreakPoint)
            {
                dividend  = dividend.ExtendTo(n * 2);
                divisor   = divisor.ExtendTo(n);
                quotient  = new IntegerNumber(new ulong[n * 2], false);
                remainder = new IntegerNumber(dividend.bits, true);
                AsmX64Operations.GetDivMod(remainder.bits, divisor.bits, n, quotient.bits, true);
                shrink(quotient);
                shrink(remainder);
                return(quotient);
            }
            bool sign = false;

            if (dividend.IsNegative != divisor.IsNegative)
            {
                dividend = IntegerNumber.Abs(dividend);
                divisor  = IntegerNumber.Abs(divisor);
                sign     = true;
            }
            else if (dividend.IsNegative && divisor.IsNegative)
            {
                dividend = -dividend;
                divisor  = -divisor;
            }

            int           delta = n - divisorDigits;
            IntegerNumber x     = (divisor << (delta * 128)).Inverse();

            quotient = dividend * x >> (n * 128);
            shrink(quotient);
            remainder = dividend - quotient * divisor;
            shrink(remainder);
            int count = 0;

            while (remainder.IsNegative)
            {
                remainder += divisor;
                quotient  -= One;
                count++;
                if (count >= 2)
                {
                    System.Diagnostics.Debugger.Break();
                }
            }
            while (remainder >= divisor)
            {
                remainder -= divisor;
                quotient  += One;
                count++;
                if (count >= 2)
                {
                    System.Diagnostics.Debugger.Break();
                }
            }

            if (sign)
            {
                quotient  = -quotient;
                remainder = -remainder;
            }
            return(quotient);
        }