用幂法计算Java中的n次根

用幂法计算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函数将舍入到可以存储为双精度的最接近的长值。您可以比较这两个结果,看看这个数字是否有整数立方根

我曾试图在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函数将舍入到可以存储为双精度的最接近的长值。您可以比较这两个结果,看看这个数字是否有整数立方根

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
    四舍五入值是否正确
  • 对支持任意精度双精度值的对象执行微积分
  • 选择1 这种方法的优点是不需要定义精度。但是,我们需要执行另一个
    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;
        }
    }