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.
精彩评论