修复算法的性能时间

huangapple go评论105阅读模式
英文:

Fixing the performance time of algorithm

问题

以下是翻译后的代码部分:

/**
 *
 * 一个用于计算整数的完全幂的实用类
 */
public class PerfectPower {
    public static void main(String[] args) {
        new TimeExec(new Runnable() {
            public void run() {
                System.out.println("17的完全幂是 " + getPerfectPower(17));
            }
        }, "获取17的完全幂", System.out).start();

        new TimeExec(new Runnable() {
            public void run() {
                System.out.println("625的完全幂是 " + getPerfectPower(625));
            }
        }, "获取625的完全幂", System.out).start();

        new TimeExec(new Runnable() {
            public void run() {
                System.out.println("1024的完全幂是 " + getPerfectPower(1024));
            }
        }, "获取1024的完全幂", System.out).start();

        new TimeExec(new Runnable() {
            public void run() {
                System.out.println("10000的完全幂是 " + getPerfectPower(10000));
            }
        }, "获取10000的完全幂", System.out).start();

        new TimeExec(new Runnable() {
            public void run() {
                System.out.println("1073741824的完全幂是 " + getPerfectPower(1073741824));
            }
        }, "获取1073741824的完全幂", System.out).start();
    }

    /**
     * 获取一个数的完全幂。
     * @param x 要计算完全幂的数。
     */
    public static int getPerfectPower(int x) {
        int largestP = 1;

        for (int b = 1; b < x; b++) {
            for (int p = 1; p < x; p++) {

                if (Math.pow(b,p) == x) {
                    largestP = p;
                }
            }
        }

        return largestP;
    }
}

以下是对应的输出部分:

17的完全幂是 1
TimeExec: 获取17的完全幂: 0.001s
625的完全幂是 2
TimeExec: 获取625的完全幂: 0.026s
1024的完全幂是 2
TimeExec: 获取1024的完全幂: 0.052s
10000的完全幂是 2
TimeExec: 获取10000的完全幂: 1.9s
1073741824的完全幂是 X
TimeExec: 获取1073741824的完全幂: XX.XXXs
英文:

The following program is created to to calculate the perfect power of numbers

The end result is to have the Perfect Power complete all test cases in under .01s of elapsed execution time.

Currently the program end result time performance is at about 2+secs for 10,000 and the one for 1073741824 takes much much longer. Need assistance to help lower the time for all perfect-powers to be .01 seconds and less.

Below is the program code:

    /**
*
* A utlity class to calculate the perfect power of an integer
*/
public class PerfectPower {
public static void main(String[] args) {
new TimeExec(new Runnable() {
public void run() {
System.out.println(&quot;Perfect Power of 17 is &quot; + getPerfectPower(17));
}
}, &quot;Get Perfect Power of 17&quot;, System.out).start();
new TimeExec(new Runnable() {
public void run() {
System.out.println(&quot;Perfect Power of 625 is &quot; + getPerfectPower(625));
}
}, &quot;Get Perfect Power of 625&quot;, System.out).start();
new TimeExec(new Runnable() {
public void run() {
System.out.println(&quot;Perfect Power of 1024 is &quot; + getPerfectPower(1024));
}
}, &quot;Get Perfect Power of 1024&quot;, System.out).start();
new TimeExec(new Runnable() {
public void run() {
System.out.println(&quot;Perfect Power of 10000 is &quot; + getPerfectPower(10000));
}
}, &quot;Get Perfect Power of 10000&quot;, System.out).start();
new TimeExec(new Runnable() {
public void run() {
System.out.println(&quot;Perfect Power of 1073741824 is &quot; + getPerfectPower(1073741824));
}
}, &quot;Get Perfect Power of 1073741824&quot;, System.out).start();	
}
/**
* Get the perfect power for a number.
* @param x number for which to calculate the perfect power.
*/
public static int getPerfectPower(int x) {
int largestP = 1;
for (int b = 1; b &lt; x; b++) {
for (int p = 1; p &lt; x; p++) {
if (Math.pow(b,p) == x) {
largestP = p;
}
}           
}
return largestP;
}
}

end code:

Perfect Power of 17 is 1
TimeExec: Get Perfect Power of 17: 0.001s

Perfect Power of 625 is 2
TimeExec: Get Perfect Power of 625: 0.026s

Perfect Power of 1024 is 2
TimeExec: Get Perfect Power of 1024: 0.052s

Perfect Power of 10000 is 2
TimeExec: Get Perfect Power of 10000: 1.9s

need this code here to print under .01s
Perfect Power of 1073741824 is X
TimeExec: Get Perfect Power of : XX.XXXs

答案1

得分: 1

首先,我们正在寻找给定参数中完全幂次数的最大*指数*。最大*指数*的最佳候选是基数为2,因此我们将循环从2开始,而不是从1开始。
其次,最小的*指数*是2(除了回退的1),因此使得*基数&lt;sup&gt;2&lt;/sup&gt; = x*的最大*基数*是*maxBase = sqrt(x)*,因此我们将在那个*基数*值结束循环。
我们的目标是公式*b&lt;sup&gt;p&lt;/sup&gt; = x*,我们从参数中得到`x`,从循环中得到`b`,所以我们可以使用*p = log(x) / log(b)*来计算`p`,然后检查它是否是整数。
避免舍入误差的最佳方法是四舍五入到最近的整数,然后检查*b&lt;sup&gt;p&lt;/sup&gt; == x*。
用于此的代码如下:
```lang-java
public static int getPerfectPower(int x) {
double maxBase = Math.sqrt(x);
for (int b = 2; b <= maxBase; b++) {
long p = Math.round(Math.log(x) / Math.log(b));
if (Math.pow(b, p) == x)
return (int) p;
}
return 1;
}

测试

public static void main(String[] args) {
test(17);
test(625);
test(1024);
test(10000);
test(1073741824);
}
static void test(int x) {
long start = System.nanoTime();
int exponent = getPerfectPower(x);
long end = System.nanoTime();
System.out.printf("Perfect Power of %d is %d (%.9fs)%n",
x, exponent, (end - start) / 1e9);
}

输出

Perfect Power of 17 is 1 (0.000022500s)
Perfect Power of 625 is 4 (0.000003700s)
Perfect Power of 1024 is 10 (0.000003700s)
Perfect Power of 10000 is 4 (0.000003500s)
Perfect Power of 1073741824 is 30 (0.000001700s)

或者,我们可以循环指数而不是基数,将时间复杂度从_O(sqrt(x))_ 更改为 O(log(x)),这在技术上更快,但这里的值太小,以至于不会注意到任何性能差异。

没有进一步的解释,以下是代码:

public static int getPerfectPower(int x) {
// x = b ^ p   &lt;==&gt;   p = log(x) / log(b)   &lt;==&gt;   b = exp(log(x) / p)
double logX = Math.log(x);
int maxExp = (int) Math.round(logX / Math.log(2));
for (int p = maxExp; p > 1; p--) {
long b = Math.round(Math.exp(logX / p));
if (Math.pow(b, p) == x)
return p;
}
return 1;
}
英文:

First, we're looking for the maximum exponent for the perfect power number given in the parameter. The best candidate for the maximum exponent is a base of 2, so we'll start the loop at 2, not 1.

Second, the smallest exponent is 2 (other than the fallback 1), so the maximum base where base<sup>2</sup> = x, is maxBase = sqrt(x), so we'll end the loop at that base value.

We're targeting the formula b<sup>p</sup> = x, and we have x from parameter and b from the loop, so we can calculate p using p = log(x) / log(b), then check if that's an integer.

Best way to do that, avoiding rounding errors, is to round to nearest integer, then checking if b<sup>p</sup> == x.

The code for that is:

public static int getPerfectPower(int x) {
double maxBase = Math.sqrt(x);
for (int b = 2; b &lt;= maxBase; b++) {
long p = Math.round(Math.log(x) / Math.log(b));
if (Math.pow(b, p) == x)
return (int) p;
}
return 1;
}

Tests

public static void main(String[] args) {
test(17);
test(625);
test(1024);
test(10000);
test(1073741824);
}
static void test(int x) {
long start = System.nanoTime();
int exponent = getPerfectPower(x);
long end = System.nanoTime();
System.out.printf(&quot;Perfect Power of %d is %d (%.9fs)%n&quot;,
x, exponent, (end - start) / 1e9);
}

Output

Perfect Power of 17 is 1 (0.000022500s)
Perfect Power of 625 is 4 (0.000003700s)
Perfect Power of 1024 is 10 (0.000003700s)
Perfect Power of 10000 is 4 (0.000003500s)
Perfect Power of 1073741824 is 30 (0.000001700s)

Alternatively, we can loop the exponent instead of the base, changing time complexity from O(sqrt(x)) to O(log(x)), which is technically faster, but the values here are too small to notice any performance difference.

Without further explanation, here's the code:

public static int getPerfectPower(int x) {
// x = b ^ p   &lt;==&gt;   p = log(x) / log(b)   &lt;==&gt;   b = exp(log(x) / p)
double logX = Math.log(x);
int maxExp = (int) Math.round(logX / Math.log(2));
for (int p = maxExp; p &gt; 1; p--) {
long b = Math.round(Math.exp(logX / p));
if (Math.pow(b, p) == x)
return p;
}
return 1;
}

答案2

得分: 0

你正在使用嵌套的两个循环从1循环到x来测试过多的情况。

对于指数 p,你可以计算最可能的底数为 b0=floor(pow(x,1.0/p))。如果你想要谨慎的话,可以测试 b=b0-1, b0, b0+1 的幂是否等于 x,但情况 b=b0-1 永远不应该成立。

然后,当达到 b0=1 时,你可以停止增加指数。

英文:

You are testing too many cases with the nested two loops from 1 to x.

For an exponent p you can compute the most likely base as b0=floor(pow(x,1.0/p)). If you want to be cautious then test the powers of b=b0-1, b0, b0+1 for being equal to x, but the case b=b0-1 should never be valid.

You can then stop increasing the exponents when b0=1 has been reached.

huangapple
  • 本文由 发表于 2020年9月19日 23:02:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/63970150.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定