Beispiel #1
0
        public BigInteger Evaluate(BigInteger n, BigInteger x0, BigInteger xmax)
        {
            if (x0 > xmax)
            {
                return(0);
            }

            sum = 0;
            if (threads == 0)
            {
                AddToSum(EvaluateInternal(n, x0, xmax));
                AddToSum(manualAlgorithm.Evaluate(n, x0, 2 * xmanual - 3));
                return(sum);
            }

            // Create consumers.
            var consumers = threads;
            var tasks     = new Task[consumers];

            for (var consumer = 0; consumer < consumers; consumer++)
            {
                var thread = consumer;
                tasks[consumer] = Task.Factory.StartNew(() => ConsumeRegions(thread));
            }

            // Produce work items.
            unprocessed = 1;
            finished.Reset();
            AddToSum(Processed(EvaluateInternal(n, x0, xmax)));
            finished.Wait();
            queue.CompleteAdding();

            // Add manual portion.
            AddToSum(manualAlgorithm.Evaluate(n, x0, 2 * xmanual - 3));

            // Wait for completion.
            Task.WaitAll(tasks);

            return(sum);
        }
Beispiel #2
0
        public 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 = BigInteger.Max(x0, BigInteger.Min(T1(C1 * BigInteger.CeilingRoot(2 * n, 3)), xmax));

#if DEBUG
            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);
                s += ProcessRegion(a1 * x2 + y2 - c5, a2 * x5 + y5 - c2, a1, 1, c5, a2, 1, c2);
                while (stack.Count > 0)
                {
                    var r = stack.Pop();
                    s += ProcessRegion(r.w, r.h, r.a1, r.b1, r.c1, r.a2, r.b2, r.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);
            s += (BigInteger)manualAlgorithm.Evaluate(n, 2 * x0 - 1, 2 * x2 - 3);
            return(s);
        }
Beispiel #3
0
        public UInt128 Evaluate(UInt128 n, UInt128 x0, UInt128 xmax)
        {
            if (x0 > xmax)
            {
                return(0);
            }

            if (n <= nMaxSimple)
            {
                return((UInt128)manualAlgorithm.Evaluate(n, x0, xmax));
            }

            if (threads == 0)
            {
                stack = new Stack <Region>();
            }
            else
            {
                queue = new BlockingCollection <Region>();
            }
            sum = 0;
#if RECORD_SIZES
            amax = 0;
            bmax = 0;
            cmax = 0;
#endif

            if (threads == 0)
            {
                AddToSum(EvaluateInternal(n, x0, xmax));
                if (xmanual > 1)
                {
                    AddToSum((UInt128)manualAlgorithm.Evaluate(n, x0, 2 * xmanual - 3));
                }
                return(sum);
            }

            // Create consumers.
            var consumers = threads;
            var tasks     = new Task[consumers];
            for (var consumer = 0; consumer < consumers; consumer++)
            {
                var thread = consumer;
                tasks[consumer] = Task.Factory.StartNew(() => ConsumeRegions(thread));
            }

            // Produce work items.
            unprocessed = 1;
            finished.Reset();
            AddToSum(Processed(EvaluateInternal(n, x0, xmax)));
            finished.Wait();
            queue.CompleteAdding();

            // Add manual portion.
            if (xmanual > 1)
            {
                AddToSum((UInt128)manualAlgorithm.Evaluate(n, x0, 2 * xmanual - 3));
            }

            // Wait for completion.
            Task.WaitAll(tasks);

#if RECORD_SIZES
            Console.WriteLine("amax = {0}, bmax = {1}, cmax = {2}", amax, bmax, cmax);
#endif
            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);
        }