Вычисление 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))
.
Ответы
Ответ 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-й корень.