获得近似平方根

时间:2017-10-13 12:45:23

标签: java algorithm math sqrt math.sqrt

我正在使用以下公式实现Babylonian方法来近似数字n的平方根:

nextGuess = (lastGuess + n / lastGuess) / 2;

因此,当nextGuesslasGuess几乎相同时,nextGuess是近似的平方根。

正在做的是检查nextGuesslastGuess是否小于非常小的数字,例如0.0001,那么我可以声称nextGuessn的近似平方根{1}}。如果不是nextGuess成为lastGuess

那我怎么能以正确的方式实现呢?

我目前的代码:

public static void getApproximatedSquare(long n){
    DecimalFormat decimalFormat = new DecimalFormat("#.####");
    decimalFormat.setRoundingMode(RoundingMode.CEILING);

    double lastGuess = 1, nextGuess;

    nextGuess = (lastGuess + n / lastGuess) / 2;
    Double init =  0.0001;
    System.out.println(decimalFormat.format(init));
    if (Double.valueOf(decimalFormat.format(nextGuess)) <= init)
        //todo

}

4 个答案:

答案 0 :(得分:4)

目前的实施草案存在一些缺陷:

  • 我怀疑你真的需要Double.valueOf(decimalFormat.format(...)),它只是从结果中删除了一些精度
  • 您的收敛条件不是nextGuess < init,而是difference_between_nextGuess_and_lastGuess < init
  • 您必须重复近似直到收敛,因此您不能只使用if。您需要forwhile或(在我的解决方案中)do... while
  • 这应该有效(在每一步,它打印上一次和下一次猜测)

    public static double getApproximatedSquare(long n) {
        DecimalFormat decimalFormat = new DecimalFormat("#.####");
        decimalFormat.setRoundingMode(RoundingMode.CEILING);
    
        double lastGuess, nextGuess = 1;
        double init = 0.0001;
        do {
            lastGuess = nextGuess;
            nextGuess = (lastGuess + (double) n / lastGuess) / 2;
            System.out.println(decimalFormat.format(lastGuess)+" ---> "+decimalFormat.format(nextGuess));
        } while (Math.abs(lastGuess - nextGuess) >= init);
        return nextGuess;
    }
    

答案 1 :(得分:1)

使用绝对容差总是一个坏主意,因为它没有考虑参数的数量级。相对误差更好。

但是在平方根的情况下,我建议采用更好的方法:确保初始近似值在精确根的√2倍内。这是通过在参数的浮点表示中将指数2减半而获得的。 (如果你不能访问这个指数,你可以通过连续的除法或乘法来获得它,直到达到[1,2]的间隔。)

示例:对于27,您有16≤27<那么1≤√27/ 4&lt; √2,你可以从4开始迭代。

然后执行巴比伦公式的四次迭代。不能少,不多了。

在该示例中,经过四次迭代后,您将获得5.19615242271,这是完全正确的。

如果你感觉连续的减半或加倍过程很慢并且认为牛顿更快,那么考虑(x + n / x)/ 2&gt; x / 2,因此牛顿实际上收敛慢于减半并涉及更多算术  !

答案 2 :(得分:0)

如果nextGuess的值100%肯定会降低并达到足够好的值,那么你不能这样做吗?

public static void getApproximatedSquare(long n){
    DecimalFormat decimalFormat = new DecimalFormat("#.####");
    decimalFormat.setRoundingMode(RoundingMode.CEILING);

    double lastGuess = n + 1;
    double nextGuess = n;
    double init      = 0.0001;

    while (lastGuess - nextGuess > init)
    {
        lastGuess = nextGuess;
        nextGuess = (lastGuess + n / lastGuess) / 2;
    }

    System.out.println(decimalFormat.format(init));
}

答案 3 :(得分:-1)

nextGuess从上面接近sqrt(n)时,您可以使用:

double lastGuess = n;
double nextGuess = n;
double epsilon = 1e-4;
while (lastGuess - nextGuess > epsilon) {
    lastGuess = nextGuess;
    nextGuess = (lastGuess + n / lastGuess) / 2;
}