private BigInteger EvaluateInternal(BigInteger n, BigInteger x0, BigInteger xmax) { this.n = n; x0 = T1(x0 + 1); xmax = T1(xmax); if (x0 > xmax) { return(0); } var ymin = YFloor(xmax); var xmin = IntegerMath.Max(x0, IntegerMath.Min(T1(C1 * IntegerMath.CeilingRoot(2 * n, 3)), xmax)); #if DIAG Console.WriteLine("n = {0}, xmin = {1}, xmax = {2}", n, xmin, xmax); #endif var s = (BigInteger)0; var a2 = (BigInteger)1; var x2 = xmax; var y2 = ymin; var c2 = a2 * x2 + y2; while (true) { var a1 = a2 + 1; var x4 = YTan(a1); var y4 = YFloor(x4); var c4 = a1 * x4 + y4; var x5 = x4 + 1; var y5 = YFloor(x5); var c5 = a1 * x5 + y5; if (x4 <= xmin) { break; } s += Triangle(c4 - c2 - x0) - Triangle(c4 - c2 - x5) + Triangle(c5 - c2 - x5); if (threads == 0) { s += ProcessRegion(0, a1 * x2 + y2 - c5, a2 * x5 + y5 - c2, a1, 1, c5, a2, 1, c2); while (queue.Count > 0) { var r = queue.Take(); s += ProcessRegion(0, r.w, r.h, r.a1, r.b1, r.c1, r.a2, r.b2, r.c2); } } else { Enqueue(new Region(a1 * x2 + y2 - c5, a2 * x5 + y5 - c2, a1, 1, c5, a2, 1, c2)); } a2 = a1; x2 = x4; y2 = y4; c2 = c4; } s += (xmax - x0 + 1) * ymin + Triangle(xmax - x0); var rest = x2 - x0; s -= y2 * rest + a2 * Triangle(rest); xmanual = x2; return(s); }
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)); }
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, 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); }