使用一组预先计算的功率来提取根

时间:2016-06-30 12:47:46

标签: java algorithm math optimization

我正在编写一个程序来解决一个十次幂问题的总和,我需要一个快速算法来查找n^10以及n^(1/10)对于自然n<1 000 000。我正在预先计算一组幂,所以n ^ 10(数组查找)需要O(1)。对于n^(1/10)我正在进行二分搜索。有没有办法加速提取超越的根?例如,如果索引是完美的幂或者保留零,则使用相应的根来制作数组和填充元素,否则将给出O(1),但是我将耗尽内存。有没有办法让根提取比O(log(n))更快?

2 个答案:

答案 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 你有两个加速我可以想到的选择:

  1. 使用不带乘法的二进制搜索

    如果您使用的是 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

  2. 您可以使用pow(x,y) = x^y = exp2(y*log2(x))

    所以x^0.1 = exp2(log2(x)/10)但是你需要这个(或定点)的大数字来看看我是怎么做的:

  3. 有关更多想法,请参阅: