开发者

how do you solve this logarithmic inequality in an efficient way?

The inequality is: nlogn <= a (n is natural number, log is based of 10). Question: what is the maximum value of n possible?

My solution is to scan n = 1 to infinity (step 1) unt开发者_开发百科il getting to the point where nlogn > a. Result returned would be n - 1

But I found out that this is not efficient when a is very large. Does anyone have a good idea how to solve it?


I did the algebra for comingstorm's solution properly and made an implementation. On my machine, Newton's method beats binary search by a factor of 4. I have tested newton() on all nonnegative 32-bit integers.

#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <time.h>

static int newton(double a) {
    if (a < 2.0 * log10(2.0)) {
        return 1;
    } else if (a < 3.0 * log10(3.0)) {
        return 2;
    }
    double a_log_10 = a * log(10);
    double x = a / log10(a);
    x = (x + a_log_10) / (1.0 + log(x));
    x = (x + a_log_10) / (1.0 + log(x));
    double n = floor(x);
    if (n * log10(n) > a) {
        n--;
    } else if ((n + 1.0) * log10(n + 1.0) <= a) {
        n++;
    }
    return n;
}

static int binarysearch(double a) {
    double l = floor(a / log10(a));
    double u = floor(a) + 1.0;
    while (1) {
        double m = floor((l + u) / 2.0);
        if (m == l) break;
        if (m * log10(m) > a) {
            u = m;
        } else {
            l = m;
        }
    }
    return l;
}

static void benchmark(const char *name, int (*solve)(double)) {
    clock_t start = clock();
    for (int a = 1 << 22; a >= 10; a--) {
        int n = solve(a);
        assert(n * log10(n) <= a);
        assert((n + 1) * log10(n + 1) > a);
    }
    printf("%s: %.2f\n", name, (clock() - start) / (double)CLOCKS_PER_SEC);
}

int main(int argc, char *argv[]) {
    benchmark("newton", newton);
    benchmark("binarysearch", binarysearch);
}


Do it with a binary search. The starting interval can be (1,a) or (sqrt(a),a).


If you solve the equation nlogn = a, you can avoid performing that calculation every time you do a comparison. The equation is a Transcendental equation, so a constant time iteration could get you a result that is a fairly good approximation. Then perform a Binary Search on your data.

procedure solve_transcendental
   n = 50
   for i = 1 .. 20
      n = a / log(n)
   end
end


Binary search is a good reliable answer. Another way to solve equations like this is to rewrite them as x=f(x) and then work out f(x), f(f(x)), f(f(f(x))) and so on, and hope that the result converges. There is hope for this if |f'(x)| < 1. Rewriting n log n = a as n = a / log n appears to work surprisingly well in practice.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜