public BigInteger Evaluate(BigInteger n) { this.n = n; if (n == 1) { return(1); } sum = 0; imax = (long)IntegerMath.FloorRoot(n, 5) / C1; xmax = imax != 0 ? Xi(imax) : (long)IntegerMath.FloorPower(n, 1, 2); mobius = new MobiusRange(xmax + 1, 0); mertens = new MertensRangeDR(mobius, Xi(1)); xi = new long[imax + 1]; mx = new long[imax + 1]; // Initialize xi (mx already initialized to zeros). for (var i = 1; i <= imax; i++) { xi[i] = Xi(i); } if (threads <= 1) { var values = new sbyte[maximumBatchSize]; var m = new long[maximumBatchSize]; Evaluate(1, xmax, values, m); } else { EvaluateParallel(1, xmax); } EvaluateTail(); return(sum); }
public BigInteger T3Slow(BigInteger n) { var sum = (BigInteger)0; var root3 = IntegerMath.FloorRoot(n, 3); if (threads == 0) { sum += T3Worker(n, root3, 0, 1); } else { var tasks = new Task[threads]; for (var i = 0; i < threads; i++) { var thread = i; tasks[i] = new Task(() => { var s = T3Worker(n, root3, thread, threads); lock (this) sum += s; }); tasks[i].Start(); } Task.WaitAll(tasks); } return(3 * sum + IntegerMath.Power(T1(root3), 3)); }
public BigInteger Evaluate(BigInteger n) { this.n = n; if (n == 1) { return(1); } sum = 0; imax = (long)IntegerMath.FloorRoot(n, 5) * C1 / C2; xmax = imax != 0 ? Xi(imax) : (long)IntegerMath.FloorPower(n, 1, 2); mobius = new MobiusRangeAdditive(xmax + 1, threads); xi = new long[imax + 1]; mx = new long[imax + 1]; // Initialize xi. for (var i = 1; i <= imax; i++) { xi[i] = Xi(i); } values = new sbyte[maximumBatchSize]; m = new int[maximumBatchSize]; m0 = 0; for (var x = (long)1; x <= xmax; x += maximumBatchSize) { m0 = EvaluateBatch(x, Math.Min(xmax, x + maximumBatchSize - 1)); } EvaluateTail(); return(sum); }
public BigInteger Evaluate(BigInteger n) { t3Map.Clear(); var jmax = IntegerMath.FloorLog(n, 2); var dmax = IntegerMath.FloorRoot(n, 3); mobius = new MobiusCollection((int)(IntegerMath.Max(jmax, dmax) + 1), 0); return(Pi3(n)); }
private int Pi2Small(long x1, long x2) { var s = F2SmallParallel(x1, x2); for (var k = 2; k <= kmax; k++) { var mu = IntegerMath.Mobius(k); if (mu != 0) { s += mu * F2Small((UInt128)IntegerMath.FloorRoot((BigInteger)n, k), x1, x2); } } return(s & 3); }
public BigInteger Pi3(BigInteger n) { var kmax = IntegerMath.FloorLog(n, 2); var sum = (BigInteger)0; for (var k = 1; k <= kmax; k++) { if (k % 3 != 0 && mobius[k] != 0) { sum += k * mobius[k] * F3(IntegerMath.FloorRoot(n, k)); } } return((sum + 1) % 3); }
public int PiWithPowers(int x) { var sum = Pi(x); for (int j = 2; true; j++) { var root = IntegerMath.FloorRoot(x, j); if (root == 1) { break; } sum += Pi(root); } return(sum); }
public BigInteger T3Slow(BigInteger n) { //Console.WriteLine("T3({0})", n); var sum = (BigInteger)0; var root3 = IntegerMath.FloorRoot(n, 3); if (threads == 0) { for (var z = (BigInteger)1; z <= root3; z++) { var nz = n / z; var sqrtnz = IntegerMath.FloorSquareRoot(nz); var t = hyperbolicSum[0].Evaluate(nz, (long)z + 1, (long)sqrtnz); sum += 2 * t - sqrtnz * sqrtnz + nz / z; } } else { var tasks = new Task[threads]; for (var i = 0; i < threads; i++) { var thread = i; tasks[i] = new Task(() => { var s = (BigInteger)0; for (var z = (BigInteger)1 + thread; z <= root3; z += threads) { var nz = n / z; var sqrtnz = IntegerMath.FloorSquareRoot(nz); var t = hyperbolicSum[thread].Evaluate(nz, (long)z + 1, (long)sqrtnz); s += 2 * t - sqrtnz * sqrtnz + nz / z; } lock (this) { sum += s; } }); tasks[i].Start(); } Task.WaitAll(tasks); } sum = 3 * sum + root3 * root3 * root3; return(sum); }
public BigInteger F3(BigInteger n) { //Console.WriteLine("F3({0})", n); var s = (BigInteger)0; var dmax = IntegerMath.FloorRoot(n, 3); for (var d = 1; d <= dmax; d += 2) { var md = mobius[d]; if (md == 0) { continue; } var term = T3(n / IntegerMath.Power((BigInteger)d, 3)); s += md * term; } Debug.Assert((s - 1) % 3 == 0); return((s - 1) / 3); }
public int ParityOfPi(BigInteger x) { // pi(x) mod 2 = SumTwoToTheOmega(x)/2 mod 2- sum(pi(floor(x^(1/j)) mod 2) if (x < piSmall.Length) { return(piSmall[(int)x] % 2); } var parity = SumTwoToTheOmega(x) / 2 % 2; for (int j = 2; true; j++) { var root = IntegerMath.FloorRoot(x, j); if (root == 1) { break; } parity ^= ParityOfPi(root); } return(parity); }
private int Pi2Medium(long x1, long x2) { Debug.Assert(x1 > IntegerMath.FloorRoot(n, 4)); return(F2Medium(n, x1, x2)); }
public Int128 Evaluate(UInt128 n) { if (n == 0) { return(0); } this.n = n; u = (long)IntegerMath.Max(IntegerMath.FloorPower(n, 2, 3) * C1 / C2, IntegerMath.CeilingSquareRoot(n)); imax = (int)(n / (ulong)u); mobius = new MobiusRangeAdditive(u + 1, threads); var batchSize = Math.Min(u, maximumBatchSize); mu = new sbyte[maximumSmallBatchSize]; m = new int[batchSize]; mx = new Int128[imax + 1]; r = new int[imax + 1]; var lmax = 0; for (var i = 1; i <= imax; i += 2) { if (wheelInclude[(i % wheelSize) >> 1]) { r[lmax++] = i; } } Array.Resize(ref r, lmax); niLarge = new UInt128[imax + 1]; niSmall = new long[imax + 1]; var buckets = Math.Max(1, threads); var costs = new double[buckets]; var bucketListsLarge = Enumerable.Range(0, buckets).Select(i => new List <int>()).ToArray(); var bucketListsSmall = Enumerable.Range(0, buckets).Select(i => new List <int>()).ToArray(); for (var l = 0; l < lmax; l++) { var i = r[l]; var ni = n / (uint)i; var large = ni > largeLimit; var cost = Math.Sqrt((double)n / i) * (large ? C7 : 1); var addto = 0; var mincost = costs[0]; for (var bucket = 0; bucket < buckets; bucket++) { if (costs[bucket] < mincost) { mincost = costs[bucket]; addto = bucket; } } niLarge[i] = ni; if (large) { bucketListsLarge[addto].Add(i); } else { niSmall[i] = (long)ni; bucketListsSmall[addto].Add(i); } costs[addto] += cost; } bucketsLarge = bucketListsLarge.Select(bucket => bucket.ToArray()).ToArray(); bucketsSmall = bucketListsSmall.Select(bucket => bucket.ToArray()).ToArray(); var m0 = 0; var xmed = Math.Min((long)IntegerMath.FloorRoot(n, 2) * C5 / C6, u); for (var x = (long)1; x <= xmed; x += maximumSmallBatchSize) { var xstart = x; var xend = Math.Min(xstart + maximumSmallBatchSize - 1, xmed); m0 = mobius.GetValuesAndSums(xstart, xend + 1, mu, m, m0); ProcessBatch(xstart, xend); } for (var x = xmed + 1; x <= u; x += maximumBatchSize) { var xstart = x; var xend = Math.Min(xstart + maximumBatchSize - 1, u); m0 = mobius.GetSums(xstart, xend + 1, m, m0); ProcessBatch(xstart, xend); } ComputeMx(); return(mx[1]); }
public Integer Evaluate(Integer n) { this.n = n; // Count lattice points under the hyperbola x*y = n. var sum = (Integer)0; // Compute the range of values over which we will apply the // geometric algorithm. xmax = IntegerMath.FloorRoot(n, 2); xmin = IntegerMath.Min(IntegerMath.FloorRoot(n, 3) * minimumMultiplier, xmax); // Calculate the line tangent to the hyperbola at the x = sqrt(n). var m2 = (Integer)1; var x2 = xmax; var y2 = n / x2; var r2 = y2 + m2 * x2; var width = x2 - xmin; Debug.Assert(r2 - m2 * x2 == y2); // Add the bottom rectangle. sum += (width + 1) * y2; // Add the isosceles right triangle corresponding to the initial // line L2 with -slope = 1. sum += width * (width + 1) / 2; // Process regions between tangent lines with integral slopes 1 & 2, // 2 & 3, etc. until we reach xmin. This provides a first // approximation to the hyperbola and accounts for the majority // of the lattice points between xmin and max. The remainder of // the points are computed by processing the regions bounded // by the two tangent lines and the hyperbola itself. while (true) { // Find the pair of points (x3, y3) and (x1, y1) where: // -H'(x3) >= the new slope // -H'(x1) <= the new slope // x1 = x3 + 1 var m1 = m2 + 1; var x3 = IntegerMath.FloorSquareRoot(n / m1); var y3 = n / x3; var r3 = y3 + m1 * x3; var x1 = x3 + 1; var y1 = n / x1; var r1 = y1 + m1 * x1; Debug.Assert(r3 - m1 * x3 == y3); Debug.Assert(r1 - m1 * x1 == y1); // Handle left-overs. if (x3 < xmin) { // Process the last few values above xmin as the number of // points above the last L2. for (var x = xmin; x < x2; x++) { sum += n / x - (r2 - m2 * x); } break; } // Invariants: // The value before x3 along L3 is on or below the hyperbola. // The value after x1 along L1 is on or below the hyperbola. // The new slope is one greater than the old slope. Debug.Assert((x3 - 1) * (r3 - m1 * (x3 - 1)) <= n); Debug.Assert((x1 + 1) * (r1 - m1 * (x1 + 1)) <= n); Debug.Assert(m1 - m2 == 1); // Add the triangular wedge above the previous slope and below the new one // and bounded on the left by xmin. var x0 = r3 - r2; width = x0 - xmin; sum += width * (width + 1) / 2; // Account for a drop or rise from L3 to L1. if (r3 != r1 && x3 < x0) { // Remove the old triangle and add the new triangle. // The formula is (ow+dr)*(ow+dr+1)/2 - ow*(ow+1)/2. var ow = x3 - x0; var dr = r3 - r1; sum += dr * (2 * ow + dr + 1) / 2; } // Determine intersection of L2 and L1. x0 = r1 - r2; var y0 = r2 - m2 * x0; Debug.Assert(r2 - m2 * x0 == r1 - m1 * x0); // Calculate width and height of parallelogram counting only lattice points. var w = (y2 - y0) + m1 * (x2 - x0); var h = (y1 - y0) + m2 * (x1 - x0); // Process the hyperbolic region bounded by L1 and L2. sum += ProcessRegion(w, h, m1, 1, m2, 1, x0, y0); // Advance to the next region. m2 = m1; x2 = x3; y2 = y3; r2 = r3; } // Process values one up to xmin. for (var x = (Integer)1; x < xmin; x++) { sum += n / x; } // Account for sqrt(n) < x <= n using the Dirichlet hyperbola method. sum = 2 * sum - xmax * xmax; return(sum); }
public Integer Evaluate(Integer n, BigInteger xfirst, BigInteger xlast) { this.n = n; // Count lattice points under the hyperbola x*y = n. var sum = (Integer)0; // Compute the range of values over which we will apply the // geometric algorithm. xmax = (Integer)xlast; xmin = IntegerMath.Max(xfirst, IntegerMath.Min(IntegerMath.FloorRoot(n, 3) * minimumMultiplier, xmax)); // Calculate the line tangent to the hyperbola at the x = sqrt(n). var m0 = (Integer)1; var x0 = xmax; var y0 = n / x0; var r0 = y0 + m0 * x0; Debug.Assert(r0 - m0 * x0 == y0); // Add the bottom rectangle. var width = x0 - xfirst; sum += (width + 1) * y0; // Add the isosceles right triangle corresponding to the initial // line L0 with -slope = 1. sum += width * (width + 1) / 2; // Process regions between tangent lines with integral slopes 1 & 2, // 2 & 3, etc. until we reach xmin. This provides a first // approximation to the hyperbola and accounts for the majority // of the lattice points between xmin and max. The remainder of // the points are computed by processing the regions bounded // by the two tangent lines and the hyperbola itself. while (true) { // Find the largest point (x1a, y1a) where -H'(X) >= the new slope. var m1 = m0 + 1; var x1a = IntegerMath.FloorSquareRoot(n / m1); var y1a = n / x1a; var r1a = y1a + m1 * x1a; var x1b = x1a + 1; var y1b = n / x1b; var r1b = y1b + m1 * x1b; Debug.Assert(r1a - m1 * x1a == y1a); Debug.Assert(r1b - m1 * x1b == y1b); // Handle left-overs. if (x1a < xmin) { // Remove all the points we added between xfirst and x0. var rest = x0 - xfirst; sum -= (r0 - m0 * x0) * rest + m0 * rest * (rest + 1) / 2; xmin = x0; break; } // Invariants: // The value before x1a along L1a is on or below the hyperbola. // The value after x1b along L2b is on or below the hyperbola. // The new slope is one greater than the old slope. Debug.Assert((x1a - 1) * (r1a - m1 * (x1a - 1)) <= n); Debug.Assert((x1b + 1) * (r1b - m1 * (x1b + 1)) <= n); Debug.Assert(m1 - m0 == 1); // Add the triangular wedge above the previous slope and below the new one // and bounded on the left by xfirst. var x0a = r1a - r0; width = x0a - xfirst; sum += width * (width + 1) / 2; // Account for a drop or rise from L1a to L1b. if (r1a != r1b && x1a < x0a) { // Remove the old triangle and add the new triangle. // The formula is (ow+dr)*(ow+dr+1)/2 - ow*(ow+1)/2. var ow = x1a - x0a; var dr = r1a - r1b; sum += dr * (2 * ow + dr + 1) / 2; } // Determine intersection of L0 and L1b. var x0b = r1b - r0; var y0b = r0 - m0 * x0b; Debug.Assert(r0 - m0 * x0b == r1b - m1 * x0b); // Calculate width and height of parallelogram counting only lattice points. var w = (y0 - y0b) + m1 * (x0 - x0b); var h = (y1b - y0b) + m0 * (x1b - x0b); // Process the hyperbolic region bounded by L1b and L0. sum += ProcessRegion(w, h, m1, 1, m0, 1, x0b, y0b); // Advance to the next region. m0 = m1; x0 = x1a; y0 = y1a; r0 = r1a; } // Process values from xfirst up to xmin. sum += manualAlgorithm.Evaluate(n, xfirst, xmin - 1); return(sum); }