コード例 #1
0
        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);
        }
コード例 #2
0
        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));
        }
コード例 #3
0
        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]);
        }
コード例 #4
0
        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);
        }