public Rational(XInt _num, XInt _den) { // If (and only if) the arithmetic supports a // *real* fast Gcd this would lead to a speed up: this.num = _num; this.den = _den; }

public Rational(long _num, long _den) { long g = Gcd(_num, _den); this.num = new XInt(_num / g); this.den = new XInt(_den / g); }

// assuming n = 2k private XInt MiddleBinomial(int n) { if (n < 50) return new XInt(Binomial[n / 2]); int k = n / 2, pc = 0, pp = 0; var rootN = XMath.FloorSqrt(n); var bigPrimes = this.sieve.GetPrimorial(k + 1, n); var smallPrimes = this.sieve.GetPrimorial(k / 2 + 1, n / 3); var primes = this.sieve.GetPrimeCollection(rootN + 1, n / 5); var primeList = new int[primes.NumberOfPrimes]; foreach (var prime in primes.Where(prime => (n / prime & 1) == 1)) { primeList[pc++] = prime; } var prodPrimes = XMath.Product(primeList, 0, pc); primes = this.sieve.GetPrimeCollection(1, rootN); var primePowers = new XInt[primes.NumberOfPrimes]; var exp = 0; foreach (var prime in primes.Where(prime => (exp = ExpSum(prime, n)) > 0)) { primePowers[pp++] = XInt.Pow(prime, exp); } var powerPrimes = XMath.Product(primePowers, 0, pp); return bigPrimes * smallPrimes * prodPrimes * powerPrimes; }

private static XInt Swing(int n) { int z; switch (n % 4) { case 1: z = n / 2 + 1; break; case 2: z = 2; break; case 3: z = 2 * (n / 2 + 2); break; default: z = 1; break; } var b = new XInt(z); z = 2 * (n - ((n + 1) & 1)); for (var i = 1; i <= n / 4; i++, z -= 4) { b = (b * z) / i; } return(b); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } if (n < 2) { return(XInt.One); } long h = n / 2; var q = h * h; var r = (n & 1) == 1 ? 2 * q * n : 2 * q; var f = new XInt(r); for (var d = 1; d < n - 2; d += 2) { f *= q -= d; } return(f); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } if (n < 2) return XInt.One; var p = XInt.One; var r = XInt.One; this.currentN = XInt.One; int h = 0, shift = 0, high = 1; var log2N = XMath.FloorLog2(n); while (h != n) { shift += h; h = n >> log2N--; var len = high; high = (h - 1) | 1; len = (high - len) / 2; if (len > 0) { p *= this.Product(len); r *= p; } } return r << shift; }

public Rational(long _num, long _den) { long cd = Gcd(_den, _num); this.num = new XInt(_num / cd); this.den = new XInt(_den / cd); }

private XInt Product(int n) { var m = n / 2; if (m == 0) return this.currentN += 2; if (n == 2) return (this.currentN += 2) * (this.currentN += 2); return this.Product(n - m) * this.Product(m); }

private XInt Swing(long n) { var s = this.gN - 1 + ((n - this.gN + 1) % 4); bool oddN = (this.gN & 1) != 1; for (; this.gN <= s; this.gN++) { if (oddN = !oddN) this.f *= this.gN; else this.f = (this.f * 4) / this.gN; } if (oddN) for (; this.gN <= n; this.gN += 4) { var m = ((this.gN + 1) * (this.gN + 3)) << 1; var d = (this.gN * (this.gN + 2)) >> 3; this.f = (this.f * m) / d; } else for (; this.gN <= n; this.gN += 4) { var m = (this.gN * (this.gN + 2)) << 1; var d = ((this.gN + 1) * (this.gN + 3)) >> 3; this.f = (this.f * m) / d; } return this.f; }

static XInt Swing(int n) { var w = XInt.One; if (n > 1) { n = n + 2; var s = new XInt[n + 1]; s[0] = s[1] = XInt.Zero; s[2] = w; for (var m = 3; m <= n; m++) { s[m] = s[m - 2]; for (var k = m; k >= 2; k--) { s[k] += s[k - 2]; if ((k & 1) == 1) // if k is odd { s[k] += s[k - 1]; } } } w = s[n]; } return(w); }

static public XInt Product(long[] seq, int start, int len) { if (len <= ThresholdProductSerial) { var rprod = new XInt(seq[start]); for (var i = start + 1; i < start + len; i++) { rprod *= seq[i]; } return(rprod); } else { var halfLen = len / 2; var rprod = XInt.Zero; var lprod = XInt.Zero; Parallel.Invoke( () => { rprod = Product(seq, start, halfLen); }, () => { lprod = Product(seq, start + halfLen, len - halfLen); } ); return(lprod * rprod); } }

static XInt Swing(int n) { var w = XInt.One; if (n > 1) { n = n + 2; var s = new XInt[n + 1]; s[0] = s[1] = XInt.Zero; s[2] = w; for (var m = 3; m <= n; m++) { s[m] = s[m - 2]; for (var k = m; k >= 2; k--) { s[k] += s[k - 2]; if ((k & 1) == 1) // if k is odd { s[k] += s[k - 1]; } } } w = s[n]; } return w; }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } int r = n % 8, s = n / 8 + 1; var rf = (long)(new int[] { 1, 1, 2, 6, 24, 120, 720, 5040 })[r]; if (n < 8) { return rf; } var factors = new XInt[s]; factors[s - 1] = rf; Parallel.For(0, s - 1, i => { factors[i] = CPpoly(i * 8 + r + 1); }); return XMath.Product(factors, 0, s); }

private XInt OddFactorial(int n) { if (n < Smallfact) { return(SmallOddFactorial[n]); } var sqrOddFact = this.OddFactorial(n / 2); XInt oddFact; if (n < Smallswing) { oddFact = XInt.Pow(sqrOddFact, 2) * SmallOddSwing[n]; } else { var ndiv4 = n / 4; var oddFactNd4 = ndiv4 < Smallfact ? SmallOddFactorial[ndiv4] : this.oddFactNdiv4; this.oddSwingTask = Task.Factory.StartNew <XInt>(() => OddSwing(n, oddFactNd4)); sqrOddFact = XInt.Pow(sqrOddFact, 2); oddFact = sqrOddFact * this.oddSwingTask.Result; } this.oddFactNdiv4 = this.oddFactNdiv2; this.oddFactNdiv2 = oddFact; return(oddFact); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } if (n < 2) { return XInt.One; } long h = n / 2; var q = h * h; var r = (n & 1) == 1 ? 2 * q * n : 2 * q; var f = new XInt(r); for (var d = 1; d < n - 2; d += 2) { f *= q -= d; } return f; }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } var s = new XInt[n + 1]; s[0] = XInt.One; for (var m = 1; m <= n; m++) { s[m] = XInt.Zero; for (var k = m; k >= 1; k--) { for (var i = 1; i <= k; i++) { s[i] += s[i - 1]; } } } return(s[n]); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } int r = n % 8, s = n / 8 + 1; var rf = (long)(new int[] { 1, 1, 2, 6, 24, 120, 720, 5040 })[r]; if (n < 8) { return(rf); } var factors = new XInt[s]; factors[s - 1] = rf; Parallel.For(0, s - 1, i => { factors[i] = CPpoly(i * 8 + r + 1); }); return(XMath.Product(factors, 0, s)); }

private XInt OddFactorial(uint n) { if (n < SmallOddFactorial.Length) { return(new XInt(SmallOddFactorial[n])); } return(XInt.Pow(this.OddFactorial(n / 2), 2) * this.OddSwing(n)); }

private XInt RecFactorial(int n) { if (n < 2) { return(XInt.One); } return(XInt.Pow(this.RecFactorial(n / 2), 2) * Swing(n)); }

static XInt OddSwing(int n, XInt oddFactNdiv4) { var len = (n - 1) / 4; if ((n % 4) != 2) len++; //-- if type(n, odd) then high = n else high = n-1. var high = n - ((n + 1) & 1); return Product(high, len) / oddFactNdiv4; }

public Rational(XInt _num, XInt _den) { // If (and only if) the arithmetic supports a // *real* fast Gcd this would lead to a speed up: // XInt cd = XInt.Gcd(_num, _den); // num = new XInt(_num / cd); // den = new XInt(_den / cd); this.num = _num; this.den = _den; }

private XInt RecFactorial(int n) { if (n < 2) { return(XInt.One); } //-- Not commutative!! return(this.Swing(n) * XInt.Pow(this.RecFactorial(n / 2), 2)); }

public XInt Factorial(int n) { if (n < 0) { throw new ArithmeticException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } this.oddFactNdiv4 = this.oddFactNdiv2 = XInt.One; return(this.OddFactorial(n) << (n - XMath.BitCount(n))); }

public XInt Factorial(int n) { if (n < 0) { throw new ArithmeticException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } this.oddFactNdiv4 = this.oddFactNdiv2 = XInt.One; return this.OddFactorial(n) << (n - XMath.BitCount(n)); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } this.gN = 1; this.f = XInt.One; return this.RecFactorial(n); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } this.gN = 1; this.f = XInt.One; return(this.RecFactorial(n)); }

private XInt RecFactorial(int n) { if (n < 2) { return(XInt.One); } if ((n & 1) == 1) { return(this.RecFactorial(n - 1) * n); } return(this.MiddleBinomial(n) * XInt.Pow(this.RecFactorial(n / 2), 2)); }

public XInt Factorial(int n) { if (n < 20) { return(XMath.Factorial(n)); } var log2N = XMath.FloorLog2(n); var j = log2N; var hN = n; this.primeList = new int[log2N][]; this.listLength = new int[log2N]; this.bound = new int[log2N]; this.tower = new int[log2N + 1]; while (true) { this.tower[j] = hN; if (hN == 1) { break; } this.bound[--j] = hN / 3; var pLen = hN < 4 ? 6 : (int)(2.0 * (XMath.FloorSqrt(hN) + (double)hN / (XMath.Log2(hN) - 1))); this.primeList[j] = new int[pLen]; hN >>= 1; } this.tower[0] = 2; this.PrimeFactors(n); var init = this.listLength[0] == 0 ? 1 : 3; var oddFactorial = new XInt(init); var results = new XInt[log2N]; Parallel.For(1, log2N, i => results[i] = XMath.Product(this.primeList[i], 0, this.listLength[i]) ); for (var i = 1; i < log2N; i++) { oddFactorial = XInt.Pow(oddFactorial, 2); oddFactorial = oddFactorial * results[i]; } return(oddFactorial << (n - XMath.BitCount(n))); }

static XInt OddSwing(int n, XInt oddFactNdiv4) { var len = (n - 1) / 4; if ((n % 4) != 2) { len++; } //-- if type(n, odd) then high = n else high = n-1. var high = n - ((n + 1) & 1); return(Product(high, len) / oddFactNdiv4); }

private XInt Product(int n) { var m = n / 2; if (m == 0) { return(this.currentN += 2); } if (n == 2) { return((this.currentN += 2) * (this.currentN += 2)); } return(this.Product(n - m) * this.Product(m)); }

private XInt RecFactorial(int n) { if (n < 2) { return(XInt.One); } var recFact = this.RecFactorial(n / 2); var sqrFact = XInt.Pow(recFact, 2); var swing = n < Smallswing ? SmallOddSwing[n] : this.swingDelegate.EndInvoke(this.results[--this.taskCounter]); return(sqrFact * swing); }

public XInt Factorial(int n) { if (n < 20) { return XMath.Factorial(n); } var log2N = XMath.FloorLog2(n); var j = log2N; var hN = n; this.primeList = new int[log2N][]; this.listLength = new int[log2N]; this.bound = new int[log2N]; this.tower = new int[log2N + 1]; while (true) { this.tower[j] = hN; if (hN == 1) break; this.bound[--j] = hN / 3; var pLen = hN < 4 ? 6 : (int)(2.0 * (XMath.FloorSqrt(hN) + (double) hN / (XMath.Log2(hN) - 1))); this.primeList[j] = new int[pLen]; hN >>= 1; } this.tower[0] = 2; this.PrimeFactors(n); var init = this.listLength[0] == 0 ? 1 : 3; var oddFactorial = new XInt(init); var results = new XInt[log2N]; Parallel.For(1, log2N, i => results[i] = XMath.Product(this.primeList[i], 0, this.listLength[i]) ); for (var i = 1; i < log2N; i++) { oddFactorial = XInt.Pow(oddFactorial, 2); oddFactorial = oddFactorial * results[i]; } return oddFactorial << (n - XMath.BitCount(n)); }

XInt IFactorialFunction.Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } if (n < 2) { return(XInt.One); } var log2N = XMath.FloorLog2(n); ProductDelegate prodDelegate = Product; var results = new IAsyncResult[log2N]; int high = n, low = n >> 1, shift = low, taskCounter = 0; // -- It is more efficient to add the big intervals // -- first and the small ones later! while ((low + 1) < high) { results[taskCounter++] = prodDelegate.BeginInvoke(low + 1, high, null, null); high = low; low >>= 1; shift += low; } XInt p = XInt.One, r = XInt.One; while (--taskCounter >= 0) { var I = Task.Factory.StartNew(() => r * p); var t = p * prodDelegate.EndInvoke(results[taskCounter]); r = I.Result; p = t; } return((r * p) << shift); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } if (n < 7) { return (XInt)(new int[] { 1, 1, 2, 6, 24, 120, 720 })[n]; } int i = 1, loop = n / 2; var f = new XInt[loop + (n & 1)]; f[0] = loop; if ((n & 1) == 1) { f[loop] = n; } XInt s = loop, t; for (var inc = loop - 1; inc > 0; inc--) { s += inc; t = s; while (t.IsEven()) { loop++; t /= 2; } f[i++] = t; } return SplitProduct(f) << loop; }

private XInt Swing(long n) { var s = this.gN - 1 + ((n - this.gN + 1) % 4); bool oddN = (this.gN & 1) != 1; for (; this.gN <= s; this.gN++) { if (oddN = !oddN) { this.f *= this.gN; } else { this.f = (this.f * 4) / this.gN; } } if (oddN) { for (; this.gN <= n; this.gN += 4) { var m = ((this.gN + 1) * (this.gN + 3)) << 1; var d = (this.gN * (this.gN + 2)) >> 3; this.f = (this.f * m) / d; } } else { for (; this.gN <= n; this.gN += 4) { var m = (this.gN * (this.gN + 2)) << 1; var d = ((this.gN + 1) * (this.gN + 3)) >> 3; this.f = (this.f * m) / d; } } return(this.f); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } if (n < 7) { return((XInt)(new int[] { 1, 1, 2, 6, 24, 120, 720 })[n]); } int i = 1, loop = n / 2; var f = new XInt[loop + (n & 1)]; f[0] = loop; if ((n & 1) == 1) { f[loop] = n; } XInt s = loop, t; for (var inc = loop - 1; inc > 0; inc--) { s += inc; t = s; while (t.IsEven()) { loop++; t /= 2; } f[i++] = t; } return(SplitProduct(f) << loop); }

private static XInt Swing(int n) { int z; switch (n % 4) { case 1: z = n / 2 + 1; break; case 2: z = 2; break; case 3: z = 2 * (n / 2 + 2); break; default: z = 1; break; } var b = new XInt(z); z = 2 * (n - ((n + 1) & 1)); for (var i = 1; i <= n / 4; i++, z -= 4) { b = (b * z) / i; } return b; }

public XInt Factorial(int n) { if (n < 20) { return(XMath.Factorial(n)); } this.sieve = new PrimeSieve(n); var log2N = XMath.FloorLog2(n); SwingDelegate swingDelegate = this.Swing; var results = new IAsyncResult[log2N]; int h = 0, shift = 0, taskCounter = 0; // -- It is more efficient to add the big intervals // -- first and the small ones later! while (h != n) { shift += h; h = n >> log2N--; if (h > 2) { results[taskCounter++] = swingDelegate.BeginInvoke(h, null, null); } } XInt p = XInt.One, r = XInt.One, rl = XInt.One; for (var i = 0; i < taskCounter; i++) { var t = rl * swingDelegate.EndInvoke(results[i]); p = p * t; rl = r; r = r * p; } return(r << shift); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } if (n < 2) { return(XInt.One); } var p = XInt.One; var r = XInt.One; this.currentN = XInt.One; int h = 0, shift = 0, high = 1; var log2N = XMath.FloorLog2(n); while (h != n) { shift += h; h = n >> log2N--; var len = high; high = (h - 1) | 1; len = (high - len) / 2; if (len > 0) { p *= this.Product(len); r *= p; } } return(r << shift); }

public XInt Factorial(int n) { if (n < 0) { throw new System.ArgumentOutOfRangeException( this.Name + ": " + nameof(n) + " >= 0 required, but was " + n); } var s = new XInt[n + 1]; s[0] = XInt.One; for (var m = 1; m <= n; m++) { s[m] = XInt.Zero; for (var k = m; k >= 1; k--) { for (var i = 1; i <= k; i++) { s[i] += s[i - 1]; } } } return s[n]; }

private static XInt CPpoly(XInt x) { // Implemented after Fredrik Johansson's arb-function // rising_fmprb_ui_bsplit_eight (please speak aloud). // x(x+1)...(x+7) = (28+98x+63x^2+14x^3+x^4)^2-16(7+2x)^2 // t = x^2, v = x^3, u = x^4 var t = x * x; var v = x * t; var u = t * t; // u = (28 + 98x + 63x^2 + 14x^3 + x^4)^2 u += v * 14u; u += t * 63u; u += x * 98u; u += 28; u *= u; // 16 (7+2x)^2 = 784 + 448x + 64x^2 u -= 784u; u -= x * 448u; u -= t << 6; return(u); }

private static XInt CPpoly(XInt x) { // Implemented after Fredrik Johansson's arb-function // rising_fmprb_ui_bsplit_eight (please speak aloud). // x(x+1)...(x+7) = (28+98x+63x^2+14x^3+x^4)^2-16(7+2x)^2 // t = x^2, v = x^3, u = x^4 var t = x * x; var v = x * t; var u = t * t; // u = (28 + 98x + 63x^2 + 14x^3 + x^4)^2 u += v * 14u; u += t * 63u; u += x * 98u; u += 28; u *= u; // 16 (7+2x)^2 = 784 + 448x + 64x^2 u -= 784u; u -= x * 448u; u -= t << 6; return u ; }

private XInt MiddleBinomial(int n) // assuming n = 2k { if (n < 50) { return(new XInt(Binomial[n / 2])); } int k = n / 2, pc = 0, pp = 0; var rootN = XMath.FloorSqrt(n); var bigPrimes = this.sieve.GetPrimorial(k + 1, n); var smallPrimes = this.sieve.GetPrimorial(k / 2 + 1, n / 3); var primes = this.sieve.GetPrimeCollection(rootN + 1, n / 5); var primeList = new int[primes.NumberOfPrimes]; foreach (var prime in primes.Where(prime => (n / prime & 1) == 1)) { primeList[pc++] = prime; } var prodPrimes = XMath.Product(primeList, 0, pc); primes = this.sieve.GetPrimeCollection(1, rootN); var primePowers = new XInt[primes.NumberOfPrimes]; var exp = 0; foreach (var prime in primes.Where(prime => (exp = ExpSum(prime, n)) > 0)) { primePowers[pp++] = XInt.Pow(prime, exp); } var powerPrimes = XMath.Product(primePowers, 0, pp); return(bigPrimes * smallPrimes * prodPrimes * powerPrimes); }

private XInt RepeatedSquare(int len, int k) { if (len == 0) { return(XInt.One); } int i = 0, mult = this.multiList[0]; while (mult > 1) { if ((mult & 1) == 1) // is mult odd ? { this.primeList[len++] = this.primeList[i]; } this.multiList[i++] = mult >> 1; mult = this.multiList[i]; } var p = XMath.Product(this.primeList, i, len - i); return(XInt.Pow(p, k) * this.RepeatedSquare(i, 2 * k)); }

public readonly XInt Value; // class { get; set; } public CachedPrimorial(int highBound, XInt val) { this.High = highBound; this.Value = val; }

readonly XInt num; // Numerator #endregion Fields #region Constructors public Rational(long _num, long _den) { long g = Gcd(_num, _den); this.num = new XInt(_num / g); this.den = new XInt(_den / g); }

private XInt OddFactorial(int n) { if (n < Smallfact) { return SmallOddFactorial[n]; } var sqrOddFact = this.OddFactorial(n / 2); XInt oddFact; if (n < Smallswing) { oddFact = XInt.Pow(sqrOddFact, 2) * SmallOddSwing[n]; } else { var ndiv4 = n / 4; var oddFactNd4 = ndiv4 < Smallfact ? SmallOddFactorial[ndiv4] : this.oddFactNdiv4; this.oddSwingTask = Task.Factory.StartNew<XInt>( () => OddSwing(n, oddFactNd4)); sqrOddFact = XInt.Pow(sqrOddFact, 2); oddFact = sqrOddFact * this.oddSwingTask.Result; } this.oddFactNdiv4 = this.oddFactNdiv2; this.oddFactNdiv2 = oddFact; return oddFact; }

readonly XInt num; // Numerator #endregion Fields #region Constructors public Rational(long _num, long _den) { long cd = Gcd(_den, _num); this.num = new XInt(_num / cd); this.den = new XInt(_den / cd); }

public readonly XInt Value; // class { get; set; } #endregion Fields #region Constructors public CachedPrimorial(int highBound, XInt val) { this.High = highBound; this.Value = val; }

static public XInt Product(long[] seq, int start, int len) { if (len <= ThresholdProductSerial) { var rprod = new XInt(seq[start]); for (var i = start + 1; i < start + len; i++) { rprod *= seq[i]; } return rprod; } else { var halfLen = len / 2; var rprod = XInt.Zero; var lprod = XInt.Zero; Parallel.Invoke( () => { rprod = Product(seq, start, halfLen); }, () => { lprod = Product(seq, start + halfLen, len - halfLen); } ); return lprod * rprod; } }