Подтвердить что ты не робот

Вычисление n-го корня в Java с использованием метода мощности

Я пытался получить кубический корень в java, используя Math.pow(n, 1.0/3), но поскольку он делит два раза, он не возвращает точный ответ. Например, с 125, это дает 4.9999999999. Для этого есть обход? Я знаю, что есть кубическая функция корня, но я хотел бы исправить это, чтобы вычислить более высокие корни.

Мне бы не хотелось раунд, потому что я хочу знать, имеет ли число целочисленный корень, делая что-то вроде этого: Math.pow(n, 1.0 / 3) % ((int) Math.pow(n, 1.0 / 3)).

4b9b3361

Ответ 1

Функция Math.round округляется до ближайшего длинного значения, которое может быть сохранено в double. Вы можете сравнить 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
}

Если это неадекватно, вы можете попробовать реализовать этот алгоритм и остановить раннее, если результат не кажется целым числом.

Ответ 2

Поскольку невозможно иметь исчисление произвольной точности с double, у вас есть три варианта:

  • Определите точность, для которой вы решите, является ли значение double целочисленным или нет.
  • Проверьте, является ли округленное значение double у вас правильным результатом.
  • Сделайте исчисление на объекте 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. Этот вопрос даст вам представление о том, как это сделать.

Ответ 3

Я бы воспользовался своей собственной функцией, чтобы сделать это, возможно, на основе этого метода.

Ответ 4

Я написал этот метод для вычисления floor(x^(1/n)), где x является неотрицательным BigInteger и n является положительным целым числом. Это было давно, поэтому я не могу объяснить, почему это работает, но я уверен, что, когда я это написал, я был счастлив, что он гарантированно дал правильный ответ достаточно быстро.

Чтобы узнать, является ли x точной мощностью n-th, вы можете проверить, вернул ли результат в power 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));

Edit Прочитав комментарии выше, я теперь помню, что это метод Ньютона-Рафсона для n-го корня. Метод Ньютона-Рафсона имеет квадратичную сходимость (что в повседневном языке означает, что это быстро). Вы можете попробовать его на цифрах, которые имеют десятки цифр, и вы должны получить ответ за долю секунды.

Вы можете адаптировать метод для работы с другими типами номеров, но double и BigDecimal, на мой взгляд, не подходят для такого рода вещей.

Ответ 5

Хорошо, это хороший выбор в этой ситуации. Вы можете положиться на это -

   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;
       }
    }

Ответ 6

Это довольно уродливый взломать, но вы можете добраться до нескольких из них с помощью отступов.

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-й корень.