Babylonian aka Heron的方法似乎是找到数n的平方根的更快算法之一。它收敛的速度取决于您的初始猜测的距离。
现在,随着数字n的百分比减少,数字n会增加其根x。
root(10):10 - 31%
10:100 - 10%
root(100):100 - 3%
root(1000):1000 - 1%
所以基本上对于数字中的每个数字除以3左右。然后使用它作为你的初始猜测。如 -
public static double root(double n ) {
//If number is 0 or negative return the number
if(n<=0)
return n ;
//call to a method to find number of digits
int num = numDigits(n) ;
double guess = n ;
//Divide by 0.3 for every digit from second digit onwards
for (int i = 0 ; i < num-1 ; ++i )
guess = guess * 0.3;
//Repeat until it converges to within margin of error
while (!(n-(guess*guess) <= 0.000001 && n-(guess*guess) >= 0 )) {
double divide = n/guess ;
guess = Math.abs(0.5*(divide+guess)) ;
}
return Math.abs(guess) ;
}
这是否有助于优化算法。这是O(n)吗?
答案 0 :(得分:0)
是。更好的方法是利用浮点表示,将二进制指数近似除以2,因为对浮点位的操作非常快。请参阅Optimized low-accuracy approximation to `rootn(x, n)`。
答案 1 :(得分:0)
我认为算法的复杂性与提供的输入无关。 (复杂性是该算法的一般特征,我们不能说算法x对于输入I1具有复杂度O1而对于输入I2具有复杂度O2)。因此,无论您提供什么初始值,都不应该提高复杂性。它可以改善该特定情况的迭代次数,但这是另一回事。将迭代次数减少一半仍然意味着相同的复杂性。请记住,n,2 * n,n / 3都适合O(n)类。
现在,关于实际的复杂性,我在维基百科上阅读了https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
This is a quadratically convergent algorithm, which means that the number of correct digits of the approximation roughly doubles with each iteration.
这意味着您需要的迭代次数与您期望的精确小数次数一样多。这是不变的。如果你需要10个精确的小数,10是一个常数,完全独立于n。
但是在维基百科的例子中,他们从最初的候选人中选择了与正确答案具有相同数量级的候选人(600与354相比)。但是,如果您的初始猜测太错误(按数量级),则需要一些额外的迭代来减少/添加必要的数字。这将增加复杂性。假设正确的答案是10000,而你的初始猜测是10.差异是4个数量级,我认为在这种情况下,达到正确幅度所需的复杂度与你猜测的数字位数之间的差异成正比。正确答案的位数。由于数字位数近似为log(n),因此在这种情况下,额外的复杂度为log(corect_answer) -log(initial_guess)
,视为绝对值。
要避免这种情况,请选择一个具有正确位数的数字,这通常是初始数字的一半数字。我最好的选择是选择数字的前半部分作为候选人(从123456,保持123,从1234567,123或1234)。在java中,您可以使用字节操作来保留数字/字符串的前半部分/保存在内存中的任何内容。因此,您不需要迭代,只需要一个具有恒定复杂度的字节操作。
答案 2 :(得分:0)
对于 n ≥4,sqrt( n )= 2 sqrt( n / 4)。对于 n &lt; 1,sqrt( n )= 1/2 sqrt( n ×4)。因此,您总是可以乘以或除以4以在范围[1,4]上标准化 n 。
一旦你这样做,取sqrt(4)= 2作为Heron算法的起点,因为这是几何平均值,每次迭代将产生最大可能的改进,并展开循环以执行所需的迭代次数为了达到理想的准确度。
最后,乘以或除以您在开头删除的所有因子2。请注意,二进制计算机可以轻松快速地乘以2或4除以。
我在my blog讨论了这个算法。