//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); }
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); }
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); }