23

我试图在 java 中使用三次方根,Math.pow(n, 1.0/3)但因为它除以双精度数,它不会返回确切的答案。例如,对于 125,这给出 4.9999999999。有解决办法吗?我知道有一个三次根函数,但我想解决这个问题,以便计算更高的根。

我不想四舍五入,因为我想通过执行以下操作来知道一个数字是否具有整数根Math.pow(n, 1.0 / 3) % ((int) Math.pow(n, 1.0 / 3))

4

9 回答 9

10

由于不可能使用 进行任意精度的微积分double,因此您有以下三种选择:

  1. 定义一个精度,您可以根据该精度决定一个double值是否为整数。
  2. 测试您所拥有的四舍五入值是否double是正确的结果。
  3. BigDecimal对支持任意精度双精度值的对象进行微积分。

选项1

private static boolean isNthRoot(int value, int n, double precision) {
    double a = Math.pow(value, 1.0 / n);
    return Math.abs(a - Math.round(a)) < precision; // if a and round(a) are "close enough" then we're good
}

这种方法的问题是如何定义“足够接近”。这是一个主观问题,取决于您的要求。

选项 2

private static boolean isNthRoot(int value, int n) {
    double a = Math.pow(value, 1.0 / n);
    return Math.pow(Math.round(a), n) == value;
}

这种方法的优点是不需要定义精度。但是,我们需要执行另一个pow操作,所以这会影响性能。

选项 3

没有内置方法来计算 BigDecimal 的双倍幂。这个问题将让您深入了解如何做到这一点。

于 2015-09-13T18:57:43.177 回答
6

Math.round函数将四舍五入到可以存储为双精度的最接近的 long 值。您可以比较 2 个结果以查看该数字是否具有整数立方根。

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
}

如果这还不够,您可以尝试实现算法,如果结果似乎不是整数,请尽早停止。

于 2015-09-13T18:33:18.170 回答
1

我会去实现我自己的功能来做到这一点,可能基于这种方法。

于 2015-09-13T18:57:50.743 回答
1

我写了这个方法来计算floor(x^(1/n))wherex是非负数BigInteger并且n是正整数。这是不久前的事了,所以我无法解释它为什么会起作用,但我有理由相信,当我写它时,我很高兴它可以保证相当快地给出正确的答案。

要查看是否x是一个精确的n-th幂,您可以检查提高到幂的结果是否再次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;
}

要使用它:

System.out.println(floorOfNthRoot(new BigInteger("125"), 3));

编辑 阅读了上面的评论后,我现在记得这是用于 n 次根的 Newton-Raphson 方法。Newton-Raphson 方法具有二次收敛性(在日常语言中意味着它很快)。您可以在具有数十位数字的数字上尝试它,您应该会在几分之一秒内得到答案。

您可以调整该方法以使用其他数字类型,但doubleBigDecimal我看来不适合这种事情。

于 2015-09-13T19:35:01.833 回答
1

这是不使用 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;
}
于 2019-01-03T09:42:52.903 回答
1

您可以使用一些来自数学领域的技巧,以获得更高的准确性。像这个 x^(1/n) = e^(lnx/n)。

在此处检查实现: https ://www.baeldung.com/java-nth-root

于 2018-10-06T11:39:17.580 回答
0

这是一个非常丑陋的 hack,但你可以通过缩进找到其中的一些。

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 个根。

于 2017-12-04T20:22:17.967 回答
0

那么在这种情况下这是一个不错的选择。你可以依靠这个——

   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;
       }
    }
于 2016-03-28T11:22:33.110 回答
0

使用二进制搜索方法查找第 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;
    }
}
于 2020-04-26T18:07:11.720 回答