用幂法计算Java中的n次根
我曾试图在java中使用用幂法计算Java中的n次根,java,math,double,decimal,root,Java,Math,Double,Decimal,Root,我曾试图在java中使用Math.pow(n,1.0/3)获得一个立方根,但由于它将双倍除法,因此无法返回准确的答案。例如,如果是125,则为4.9999999。这有什么办法吗?我知道有一个立方根函数,但我想修正它,这样我可以计算更高的根 我不想舍入,因为我想通过这样的操作来知道一个数字是否有整数根:Math.pow(n,1.0/3)%((int)Math.pow(n,1.0/3))Math.round函数将舍入到可以存储为双精度的最接近的长值。您可以比较这两个结果,看看这个数字是否有整数立方根
Math.pow(n,1.0/3)
获得一个立方根,但由于它将双倍除法,因此无法返回准确的答案。例如,如果是125,则为4.9999999。这有什么办法吗?我知道有一个立方根函数,但我想修正它,这样我可以计算更高的根
我不想舍入,因为我想通过这样的操作来知道一个数字是否有整数根:Math.pow(n,1.0/3)%((int)Math.pow(n,1.0/3))
Math.round函数将舍入到可以存储为双精度的最接近的长值。您可以比较这两个结果,看看这个数字是否有整数立方根
double dres = Math.pow(125, 1.0 / 3.0);
double ires = Math.round(dres);
double diff = Math.abs(dres - ires);
if (diff < Math.ulp(10.0)) {
// has cubic root
}
double-dres=Math.pow(125,1.0/3.0);
双ires=数学四舍五入(dres);
双差=数学绝对值(dres-ires);
如果(差异<数学ulp(10.0)){
//有立方根
}
如果这还不够,您可以尝试实现算法,如果结果似乎不是整数,则可以提前停止。由于不可能使用
双精度
进行任意精度演算,您有三种选择:
双精度值是否为整数
double
四舍五入值是否正确pow
操作,因此这将影响性能
选择3
没有内置的方法来计算BigDecimal的二次幂。将为您提供有关如何执行的见解。我将实现自己的函数来执行此操作,可能基于方法。我编写此方法是为了计算
floor(x^(1/n))
其中x
是一个非负biginger
和n
是一个正整数。这是很久以前的事了,所以我无法解释它为什么会起作用,但我有理由相信,当我写这篇文章时,我很高兴它保证能很快给出正确的答案
要查看x
是否为精确的n次
幂,您可以检查提升到幂n
的结果是否再次精确返回x
public static BigInteger floorOfNthRoot(BigInteger x, int n) {
int sign = x.signum();
if (n <= 0 || (sign < 0))
throw new IllegalArgumentException();
if (sign == 0)
return BigInteger.ZERO;
if (n == 1)
return x;
BigInteger a;
BigInteger bigN = BigInteger.valueOf(n);
BigInteger bigNMinusOne = BigInteger.valueOf(n - 1);
BigInteger b = BigInteger.ZERO.setBit(1 + x.bitLength() / n);
do {
a = b;
b = a.multiply(bigNMinusOne).add(x.divide(a.pow(n - 1))).divide(bigN);
} while (b.compareTo(a) == -1);
return a;
}
编辑
读了上面的评论后,我现在记得这是牛顿-拉斐逊法求n次根。Newton-Raphson方法具有二次收敛性(这在日常语言中意味着它很快)。你可以在有几十个数字的数字上试一下,你会在几分之一秒内得到答案
您可以调整该方法以处理其他数字类型,但在我看来,
double
和BigDecimal
不适合这种情况。在这种情况下,这是一个很好的选择。
你可以相信这一点-
System.out.println(" ");
System.out.println(" Enter a base and then nth root");
while(true)
{
a=Double.parseDouble(br.readLine());
b=Double.parseDouble(br.readLine());
double negodd=-(Math.pow((Math.abs(a)),(1.0/b)));
double poseve=Math.pow(a,(1.0/b));
double posodd=Math.pow(a,(1.0/b));
if(a<0 && b%2==0)
{
String io="\u03AF";
double negeve=Math.pow((Math.abs(a)),(1.0/b));
System.out.println(" Root is imaginary and value= "+negeve+" "+io);
}
else if(a<0 && b%2==1)
System.out.println(" Value= "+negodd);
else if(a>0 && b%2==0)
System.out.println(" Value= "+poseve);
else if(a>0 && b%2==1)
System.out.println(" Value= "+posodd);
System.out.println(" ");
System.out.print(" Enter '0' to come back or press any number to continue- ");
con=Integer.parseInt(br.readLine());
if(con==0)
break;
else
{
System.out.println(" Enter a base and then nth root");
continue;
}
}
System.out.println(“”);
System.out.println(“输入一个基数,然后输入第n个根”);
while(true)
{
a=Double.parseDouble(br.readLine());
b=Double.parseDouble(br.readLine());
双负奇数=-(数学功率((数学绝对值(a)),(1.0/b));
双Posev=数学功率(a,(1.0/b));
double posodd=数学功率(a,(1.0/b));
如果(a0&&b%2==1)
System.out.println(“Value=“+posodd”);
System.out.println(“”);
System.out.print(“输入“0”返回或按任意数字继续-”;
con=Integer.parseInt(br.readLine());
如果(con==0)
打破
其他的
{
System.out.println(“输入一个基数,然后输入第n个根”);
继续;
}
}
这是一个相当难看的黑客攻击,但你可以通过缩进来达到其中的一些
System.out.println(Math.sqrt(Math.sqrt(256)));
System.out.println(Math.pow(4, 4));
System.out.println(Math.pow(4, 9));
System.out.println(Math.cbrt(Math.cbrt(262144)));
Result:
4.0
256.0
262144.0
4.0
这将给出每个n^3立方体和每个n^2根。您可以使用一些来自数学领域的技巧,以获得更高的精度。 就像这个x^(1/n)=e^(lnx/n) 检查此处的实现:
以下是不使用Java的Math.pow函数的解决方案。 它会给你近N根
public class NthRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testcases = scanner.nextInt();
while (testcases-- > 0) {
int root = scanner.nextInt();
int number = scanner.nextInt();
double rootValue = compute(number, root) * 1000.0 / 1000.0;
System.out.println((int) rootValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static double compute(int number, int root) {
double xPre = Math.random() % 10;
double error = 0.0000001;
double delX = 2147483647;
double current = 0.0;
while (delX > error) {
current = ((root - 1.0) * xPre + (double) number / Math.pow(xPre, root - 1)) / (double) root;
delX = Math.abs(current - xPre);
xPre = current;
}
return current;
}
使用二进制搜索方法查找第n个根。
以下是根据您的要求以任意精度查找第n个根的方法
import java.util.Scanner;
public class FindRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testCase = scanner.nextInt();
while (testCase-- > 0) {
double number = scanner.nextDouble();
int root = scanner.nextInt();
double precision = scanner.nextDouble();
double result = findRoot(number, root, precision);
System.out.println(result);
}
}
}
private static double findRoot(double number, int root, double precision) {
double start = 0;
double end = number / 2;
double mid = end;
while (true) {
if (precision >= diff(number, mid, root)) {
return mid;
}
if (pow(mid, root) > number) {
end = mid;
} else {
start = mid;
}
mid = (start + end) / 2;
}
}
private static double diff(double number, double mid, int n) {
double power = pow(mid, n);
return number > power ? number - power : power - number;
}
private static double pow(double number, int pow) {
double result = number;
while (pow-- > 1) {
result *= number;
}
return result;
}
}
使用BigDecimal类,它是具有任意精度的实数的十进制表示。当然,在BigDecimal类中没有计算n个根的方法。所以你需要自己去实现它。我会给牛顿-拉夫森方法一个机会。看。我知道这是正确的,但我不能这样做,因为我需要确保这个数字是整数根,我刚刚编辑了这个问题以包括这个。这是问题中已经提到的。他,;It’没有得到确切的结果,也不想对结果进行取整。@RamanShrivastava我根据编辑的答案编辑了答案question@ManosNikolaidis非常感谢。这个问题更多的是关于双精度的定义方式,而不是所使用的方法。哪一个更有用?
System.out.println(Math.sqrt(Math.sqrt(256)));
System.out.println(Math.pow(4, 4));
System.out.println(Math.pow(4, 9));
System.out.println(Math.cbrt(Math.cbrt(262144)));
Result:
4.0
256.0
262144.0
4.0
public class NthRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testcases = scanner.nextInt();
while (testcases-- > 0) {
int root = scanner.nextInt();
int number = scanner.nextInt();
double rootValue = compute(number, root) * 1000.0 / 1000.0;
System.out.println((int) rootValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static double compute(int number, int root) {
double xPre = Math.random() % 10;
double error = 0.0000001;
double delX = 2147483647;
double current = 0.0;
while (delX > error) {
current = ((root - 1.0) * xPre + (double) number / Math.pow(xPre, root - 1)) / (double) root;
delX = Math.abs(current - xPre);
xPre = current;
}
return current;
}
import java.util.Scanner;
public class FindRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testCase = scanner.nextInt();
while (testCase-- > 0) {
double number = scanner.nextDouble();
int root = scanner.nextInt();
double precision = scanner.nextDouble();
double result = findRoot(number, root, precision);
System.out.println(result);
}
}
}
private static double findRoot(double number, int root, double precision) {
double start = 0;
double end = number / 2;
double mid = end;
while (true) {
if (precision >= diff(number, mid, root)) {
return mid;
}
if (pow(mid, root) > number) {
end = mid;
} else {
start = mid;
}
mid = (start + end) / 2;
}
}
private static double diff(double number, double mid, int n) {
double power = pow(mid, n);
return number > power ? number - power : power - number;
}
private static double pow(double number, int pow) {
double result = number;
while (pow-- > 1) {
result *= number;
}
return result;
}
}