我正在编写一个程序来解决一个十次幂问题的总和,我需要一个快速算法来查找n^10
以及n^(1/10)
对于自然n<1 000 000
。我正在预先计算一组幂,所以n ^ 10(数组查找)需要O(1)。对于n^(1/10)
我正在进行二分搜索。有没有办法加速提取超越的根?例如,如果索引是完美的幂或者保留零,则使用相应的根来制作数组和填充元素,否则将给出O(1),但是我将耗尽内存。有没有办法让根提取比O(log(n))更快?
答案 0 :(得分:0)
为什么根数组的内存不足?如果它与幂数组的大小相同,则它将使用相同的数据类型。但是对于权力,(10 ^ 6)^ 10 = 10 ^ 60,这不适合长变量,因此您需要使用biginteger或bigdecimal类型。如果您的数字n
大于您的记忆所能承受的最大数组大小n_max,您可以将n
除以n_m直到它适合,即拆分n = n_max ^ m * k,其中m是a自然数和k < N_MAX:
public class Roots
{
static final int N_MAX = 1_000_000;
double[] roots = new double[N_MAX+1];
Roots() {for (int i = 0; i <= N_MAX; i++) {roots[i] = Math.pow(i, 0.1);}}
double root(long n)
{
int m = 0;
while (n > N_MAX)
{
n /= N_MAX;
m++;
}
return (Math.pow(roots[N_MAX],m)*roots[(int)n]); // in a real case you would precompute pow(roots[N_MAX],m) as well
}
static public void main(String[] args)
{
Roots root = new Roots();
System.out.println(root.root(1000));
System.out.println(root.root(100_000_000_000_000l));
}
}
答案 1 :(得分:0)
除了 LUT 你有两个加速我可以想到的选择:
使用不带乘法的二进制搜索
如果您使用的是 bignums ,则10-root二进制搜索搜索不再是O(log(n))
,因为其中使用的基本操作不再是O(1)
!例如,+,-,<<,>>,|,&,^,>=,<=,>,<,==,!=
将成为O(b)
,*
将O(b^2)
或O(b.log(b))
其中b=log(n)
取决于所使用的算法(甚至操作数幅度)。因此,天真的二进制搜索根查找将是更好的情况O(log^2(n).log(log(n)))
要加速它,你可以尝试不使用乘法。是的,这是可能的,最终的复杂性将是O(log^2(n))
看看:
要了解如何实现这一目标。区别仅在于求解不同的方程:
x1 = x0+m
x1^10 = f(x0,m)
如果以代数x1=f(x0,m)
获得,则内部的每个乘法转换为位移并添加...例如10*x = x<<1 + x<<3
。 LUT 表不是必需的,因为您可以在二进制搜索期间迭代它。
我想f(x0,m)
将包含x0
的较小权力,所以类比地计算所有需要的权力......所以最终的结果将没有动力。抱歉,懒得为你做,你可以使用一些数学应用程序,如Derive for Windows
您可以使用pow(x,y) = x^y = exp2(y*log2(x))
所以x^0.1 = exp2(log2(x)/10)
但是你需要这个(或定点)的大数字来看看我是怎么做的:
有关更多想法,请参阅: