private void Evaluate(long x1, long x2, sbyte[] values, long[] m)
        {
#if TIMER
            var timer = new ThreadStopwatch();
            timer.Restart();
#endif
            var length = x2 - x1 + 1;
            var batches = (length + m.Length - 1) / m.Length;
            var batchSize = (length + batches - 1) / batches;
            var m0 = mertens.Evaluate(x1 - 1);
            var x = x1;
            while (x <= x2)
            {
                m0 = EvaluateBatch(x, Math.Min(x + batchSize - 1, x2), values, m, m0);
                x += batchSize;
            }
#if TIMER
            Console.WriteLine("x1 = {0:F3}, length = {1:F3}, elapsed = {2:F3} msec",
                (double)x1, (double)(x2 - x1 + 1), (double)timer.ElapsedTicks / ThreadStopwatch.Frequency * 1000);
#endif
        }
        private void UpdateMx(long x1, long x2, int[] r)
        {
            #if TIMER
            var timer = new ThreadStopwatch();
            timer.Restart();
            #endif
            for (var l = 0; l < r.Length; l++)
            {
                var i = r[l];
                var x = n / i;
                var sqrt = IntegerMath.FloorSquareRoot(x);
                var xover = Math.Min(sqrt * C3 / C4, x);
                xover = x / (x / xover);
                var s = (long)0;

                var jmin = UpToOdd(Math.Max(imax / i + 1, x / (x2 + 1) + 1));
                var jmax = DownToOdd(Math.Min(xover, x / x1));
                //s += JSum1(x, jmin, ref jmax, x1);
                s += JSum2(x, jmin, jmax, x1);

                var kmin = Math.Max(1, x1);
                var kmax = Math.Min(x / xover - 1, x2);
                s += KSum1(x, kmin, ref kmax, x1);
                s += KSum2(x, kmin, kmax, x1);

                mx[i] -= s;
            }
            #if TIMER
            Console.WriteLine("x1 = {0:F3}, length = {1:F3}, elapsed = {2:F3} msec",
                (double)x1, (double)(x2 - x1 + 1), (double)timer.ElapsedTicks / ThreadStopwatch.Frequency * 1000);
            #endif
        }