Ejemplo n.º 1
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);
        }
Ejemplo n.º 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);
        }
Ejemplo n.º 3
0
        public static bool UnitTest()
        {
            //    SPECIAL prime: 2^64 - 2^32 + 1
            //prime: 2^64 - 2^34 + 1
            //prime: 2^64 - 2^40 + 1
            //    SPECIAL prime: 2 ^ 128 - 2 ^ 54 + 1
            //prime: 2 ^ 128 - 2 ^ 108 + 1
            //prime: 2 ^ 256 - 2 ^ 168 + 1
            //prime: 2 ^ 256 - 2 ^ 174 + 1
            //prime: 2 ^ 512 - 2 ^ 32 + 1
            //prime: 2 ^ 512 - 2 ^ 288 + 1
            //    SPECIAL prime: 2 ^ 1024 - 2 ^ 142 + 1
            //    SPECIAL prime: 2 ^ 1024 - 2 ^ 226 + 1
            //prime: 2 ^ 1024 - 2 ^ 562 + 1
            //prime: 2 ^ 1024 - 2 ^ 718 + 1
            //prime: 2 ^ 1024 - 2 ^ 856 + 1
            //prime: 2 ^ 1024 - 2 ^ 880 + 1
            //prime: 2 ^ 4096 - 2 ^ 3510 + 1
            //prime: 2 ^ 4096 - 2 ^ 3708 + 1
            if ("not exec".Trim() == "exec")
            {
                StringBuilder primes = new StringBuilder();
                for (int exp = 6; exp <= 12; exp++)
                {
                    int shift = 1 << exp;
                    Parallel.For(32, shift, i =>
                    {
                        ulong[] baseValue   = new ulong[shift / 64];
                        ulong[] expValue    = new ulong[shift / 64];
                        ulong[] modulo      = new ulong[shift / 64];
                        ulong[] subtractor  = new ulong[shift / 64];
                        ulong[] one         = new ulong[shift / 64];
                        ulong[] pPlusOne    = new ulong[shift / 64];
                        subtractor[i / 64] |= 1UL << (i & 63);
                        modulo[0]           = 1UL;
                        one[0]              = 1UL;
                        AsmX64Operations.Subtract(modulo, subtractor, modulo, 0, modulo.Length);
                        modulo.CopyTo(expValue, 0);
                        modulo.CopyTo(pPlusOne, 0);
                        expValue[0]--;
                        pPlusOne[0]++;

                        int isPrime = 1;
                        for (int a = 2; a <= 128; a++)
                        {
                            one.CopyTo(baseValue, 0);
                            baseValue[0] = (ulong)a;
                            AsmX64Operations.ModularExponentiation(baseValue, expValue, modulo, modulo.Length, 5);
                            if (Enumerable.Range(0, modulo.Length).All(idx => baseValue[idx] == one[idx]) ||
                                Enumerable.Range(0, modulo.Length).All(idx => baseValue[idx] == pPlusOne[idx]))
                            {
                                continue;
                            }
                            isPrime = 0;
                            break;
                        }

                        if (isPrime != 0)
                        {
                            lock (primes)
                            {
                                primes.AppendLine("prime: 2^" + shift.ToString() + " - 2^" + i.ToString() + " + 1");
                            }
                        }
                    });
                }
                Clipboard.SetText(primes.ToString());
                System.Windows.Forms.MessageBox.Show(primes.ToString(), "message");
            }

            Random     random = new Random(1002);
            BigInteger maxx   = 0;
            BigInteger minn   = 0;
            bool       ok     = true;

            for (int i = 2; --i >= 0;)
            {
                byte[] bytes1 = new byte[112 * 8 + random.Next(32 * 8)];
                byte[] bytes2 = new byte[112 * 8 + random.Next(32 * 8)];
                random.NextBytes(bytes1);
                random.NextBytes(bytes2);

                BigInteger    n1 = new BigInteger(bytes1);
                BigInteger    n2 = new BigInteger(bytes2);
                IntegerNumber f1 = new IntegerNumber(bytes1);
                IntegerNumber f2 = new IntegerNumber(bytes2);
                if (n1.ToString() != f1.ToString())
                {
                    ok = false;
                }
                if (n2.ToString() != f2.ToString())
                {
                    ok = false;
                }

                BigInteger    a1 = n1 + n2;
                IntegerNumber a2 = f1 + f2;
                if (a1.ToString() != a2.ToString())
                {
                    ok = false;
                }

                BigInteger    s1 = n1 - n2;
                IntegerNumber s2 = f1 - f2;
                if (s1.ToString() != s2.ToString())
                {
                    ok = false;
                }

                BigInteger    m1 = n1 * n2;
                IntegerNumber m2 = f1 * f2;
                if (m1.ToString() != m2.ToString())
                {
                    ok = false;
                }

                int           shrvalue = random.Next(256) + 1;
                BigInteger    sh1      = n1 >> shrvalue;
                IntegerNumber sh2      = f1 >> shrvalue;
                if (sh1.ToString() != sh2.ToString())
                {
                    ok = false;
                }
                if ((-f1).ToString() != (-n1).ToString() || (-f2).ToString() != (-n2).ToString())
                {
                    ok = false;
                }

                int           shlvalue = random.Next(256) + 1;
                BigInteger    shl1     = n1 << shlvalue;
                IntegerNumber shl2     = f1 << shlvalue;
                if (shl1.ToString() != shl2.ToString())
                {
                    ok = false;
                }

                byte[] bytesINV = new byte[(192 + 32) * 8 + random.Next(64 * 8)];
                random.NextBytes(bytesINV);
                BigInteger    num1 = new BigInteger(bytesINV);
                IntegerNumber num2 = new IntegerNumber(bytesINV);
                if (num1.ToString() != num2.ToString())
                {
                    ok = false;
                }
                BigInteger    inv0 = (BigInteger.One << (num2.Digits * 64 * 2)) / num1;
                IntegerNumber inv1 = num2.Inverse();
                if (inv0.ToString() != inv1.ToString())
                {
                    ok = false;
                }

                byte[] bytes4 = new byte[bytes1.Length * 4];
                random.NextBytes(bytes4);
                BigInteger    n4  = new BigInteger(bytes4);
                IntegerNumber f4  = new IntegerNumber(bytes4);
                BigInteger    qb4 = n4 / n1;
                IntegerNumber qn4 = f4 / f1;
                if (qb4.ToString() != qn4.ToString())
                {
                    ok = false;
                }
                byte[] bytes3 = new byte[(bytes1.Length + bytes2.Length) & -8];
                random.NextBytes(bytes3);
                BigInteger    square1 = BigInteger.Abs(new BigInteger(bytes3));
                IntegerNumber square2 = IntegerNumber.Abs(new IntegerNumber(bytes3));
                BigInteger    root1   = square1.Sqrt();
                IntegerNumber root2   = square2.Sqrt();
                if (root1.ToString() != root2.ToString())
                {
                    ok = false;
                }
                if (!ok)
                {
                    break;
                }
            }
            return(ok);
        }