我正在尝试用Java编写一个计算数字第n个根的函数。我正在使用牛顿的方法。但是,用户应该能够指定他们想要的精度位数。这是我遇到麻烦的部分,因为我的回答往往不完全正确。相关代码位于:http://pastebin.com/d3rdpLW8。我怎么能修复这个代码,以便它总是给出至少p位精度的答案? (没有做必要的工作)
import java.util.Random;
public final class Compute {
private Compute() {
}
public static void main(String[] args) {
Random rand = new Random(1230);
for (int i = 0; i < 500000; i++) {
double k = rand.nextDouble()/100;
int n = (int)(rand.nextDouble() * 20) + 1;
int p = (int)(rand.nextDouble() * 10) + 1;
double math = n == 0 ? 1d : Math.pow(k, 1d / n);
double compute = Compute.root(n, k, p);
if(!String.format("%."+p+"f", math).equals(String.format("%."+p+"f", compute))) {
System.out.println(String.format("%."+p+"f", math));
System.out.println(String.format("%."+p+"f", compute));
System.out.println(math + " " + compute + " " + p);
}
}
}
/**
* Returns the n-th root of a positive double k, accurate to p decimal
* digits.
*
* @param n
* the degree of the root.
* @param k
* the number to be rooted.
* @param p
* the decimal digit precision.
* @return the n-th root of k
*/
public static double root(int n, double k, int p) {
double epsilon = pow(0.1, p+2);
double approx = estimate_root(n, k);
double approx_prev;
do {
approx_prev = approx;
// f(x) / f'(x) = (x^n - k) / (n * x^(n-1)) = (x - k/x^(n-1)) / n
approx -= (approx - k / pow(approx, n-1)) / n;
} while (abs(approx - approx_prev) > epsilon);
return approx;
}
private static double pow(double x, int y) {
if (y == 0)
return 1d;
if (y == 1)
return x;
double k = pow(x * x, y >> 1);
return (y & 1) == 0 ? k : k * x;
}
private static double abs(double x) {
return Double.longBitsToDouble((Double.doubleToLongBits(x) << 1) >>> 1);
}
private static double estimate_root(int n, double k) {
// Extract the exponent from k.
long exp = (Double.doubleToLongBits(k) & 0x7ff0000000000000L);
// Format the exponent properly.
int D = (int) ((exp >> 52) - 1023);
// Calculate and return 2^(D/n).
return Double.longBitsToDouble((D / n + 1023L) << 52);
}
}
答案 0 :(得分:3)
如果你想要4位小数的精度,只需迭代直到更新小于0.0001。
也就是说,如果您想要Math.pow(10, -n)
精度数字,请将您的epsilon设置为n
。
答案 1 :(得分:2)
让我们回想一下牛顿方法的误差分析。基本上,它给第一次迭代的误差作为第n-1次迭代误差的函数。
那么,我们如何判断错误是否小于k?我们不能,除非我们知道e(0)处的错误。如果我们知道e(0)处的错误,我们就会用它来找到正确的答案。
你能做的就是说“e(0)&lt; = m”。然后你可以找到n,使得e(n)&lt; = k为你想要的k。但是,这需要知道半径中f''的最大值,这通常与查找x截距一样困难。
您正在检查的是,如果错误的变化小于k,这是一种完全可以接受的方式。但它没有检查错误是否小于k。正如Axel和其他人所指出的那样,还有许多其他的根近似算法,其中一些会产生更容易的错误分析,如果你真的想要这个,你应该使用其中一种。
答案 2 :(得分:0)
您的代码中存在错误。您的pow()
方法的最后一行应该是读取的
return (y & 1) == 1 ? k : k * x;
而不是
return (y & 1) == 0 ? k : k * x;