Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/java.base/share/classes/java/math/BigInteger.java
Original file line number Diff line number Diff line change
Expand Up @@ -2768,17 +2768,17 @@ public BigInteger[] sqrtAndRemainder() {
* @throws ArithmeticException if {@code n} is even and {@code this} is negative.
* @see #sqrt()
* @since 26
* @apiNote Note that calling {@code nthRoot(2)} is equivalent to calling {@code sqrt()}.
* @apiNote Note that calling {@code rootn(2)} is equivalent to calling {@code sqrt()}.
*/
public BigInteger nthRoot(int n) {
public BigInteger rootn(int n) {
if (n == 1)
return this;

if (n == 2)
return sqrt();

checkRootDegree(n);
return new MutableBigInteger(this.mag).nthRootRem(n)[0].toBigInteger(signum);
return new MutableBigInteger(this.mag).rootnRem(n)[0].toBigInteger(signum);
}

/**
Expand All @@ -2793,20 +2793,20 @@ public BigInteger nthRoot(int n) {
* @throws ArithmeticException if {@code n} is even and {@code this} is negative.
* @see #sqrt()
* @see #sqrtAndRemainder()
* @see #nthRoot(int)
* @see #rootn(int)
* @since 26
* @apiNote Note that calling {@code nthRootAndRemainder(2)} is equivalent to calling
* @apiNote Note that calling {@code rootnAndRemainder(2)} is equivalent to calling
* {@code sqrtAndRemainder()}.
*/
public BigInteger[] nthRootAndRemainder(int n) {
public BigInteger[] rootnAndRemainder(int n) {
if (n == 1)
return new BigInteger[] { this, ZERO };

if (n == 2)
return sqrtAndRemainder();

checkRootDegree(n);
MutableBigInteger[] rootRem = new MutableBigInteger(this.mag).nthRootRem(n);
MutableBigInteger[] rootRem = new MutableBigInteger(this.mag).rootnRem(n);
return new BigInteger[] {
rootRem[0].toBigInteger(signum),
rootRem[1].toBigInteger(signum)
Expand Down
16 changes: 8 additions & 8 deletions src/java.base/share/classes/java/math/MutableBigInteger.java
Original file line number Diff line number Diff line change
Expand Up @@ -1906,7 +1906,7 @@ private boolean unsignedLongCompare(long one, long two) {
* @param n the root degree
* @return the integer {@code n}th root of {@code this} and the remainder
*/
MutableBigInteger[] nthRootRem(int n) {
MutableBigInteger[] rootnRem(int n) {
// Special cases.
if (this.isZero() || this.isOne())
return new MutableBigInteger[] { this, new MutableBigInteger() };
Expand All @@ -1923,7 +1923,7 @@ MutableBigInteger[] nthRootRem(int n) {
if (bitLength <= Long.SIZE) {
// Initial estimate is the root of the unsigned long value.
final long x = this.toLong();
long sLong = (long) nthRootApprox(Math.nextUp(x >= 0 ? x : x + 0x1p64), n) + 1L;
long sLong = (long) rootnApprox(Math.nextUp(x >= 0 ? x : x + 0x1p64), n) + 1L;
/* The integer-valued recurrence formula in the algorithm of Brent&Zimmermann
* simply discards the fraction part of the real-valued Newton recurrence
* on the function f discussed in the referenced work.
Expand Down Expand Up @@ -1996,7 +1996,7 @@ MutableBigInteger[] nthRootRem(int n) {
// Use the root of the shifted value as an estimate.
// rad ≤ 2^ME, so Math.nextUp(rad) < Double.MAX_VALUE
rad = Math.nextUp(rad);
approx = nthRootApprox(rad, n);
approx = rootnApprox(rad, n);
} else { // fp arithmetic gives too few correct bits
// Set the root shift to the root's bit length minus 1
// The initial estimate will be 2^rootLen == 2 << (rootLen - 1)
Expand Down Expand Up @@ -2050,7 +2050,7 @@ MutableBigInteger[] nthRootRem(int n) {
MutableBigInteger x = new MutableBigInteger(this);
x.rightShift(rootSh * n);

newtonRecurrenceNthRoot(x, s, n, s.toBigInteger().pow(n - 1));
newtonRecurrenceRootn(x, s, n, s.toBigInteger().pow(n - 1));
s.add(ONE); // round up to ensure s is an upper bound of the root
}

Expand All @@ -2060,7 +2060,7 @@ MutableBigInteger[] nthRootRem(int n) {
}

// Do the 1st iteration outside the loop to ensure an overestimate
newtonRecurrenceNthRoot(this, s, n, s.toBigInteger().pow(n - 1));
newtonRecurrenceRootn(this, s, n, s.toBigInteger().pow(n - 1));
// Refine the estimate.
do {
BigInteger sBig = s.toBigInteger();
Expand All @@ -2069,18 +2069,18 @@ MutableBigInteger[] nthRootRem(int n) {
if (rem.subtract(this) <= 0)
return new MutableBigInteger[] { s, rem };

newtonRecurrenceNthRoot(this, s, n, sToN1);
newtonRecurrenceRootn(this, s, n, sToN1);
} while (true);
}

private static double nthRootApprox(double x, int n) {
private static double rootnApprox(double x, int n) {
return Math.nextUp(n == 3 ? Math.cbrt(x) : Math.pow(x, Math.nextUp(1.0 / n)));
}

/**
* Computes {@code ((n-1)*s + x/sToN1)/n} and places the result in {@code s}.
*/
private static void newtonRecurrenceNthRoot(
private static void newtonRecurrenceRootn(
MutableBigInteger x, MutableBigInteger s, int n, BigInteger sToN1) {
MutableBigInteger dividend = new MutableBigInteger();
s.mul(n - 1, dividend);
Expand Down
88 changes: 44 additions & 44 deletions test/jdk/java/math/BigInteger/BigIntegerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/*
* @test
* @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465
* 8074460 8078672 8032027 8229845 8077587 8367365
* 8074460 8078672 8032027 8229845 8077587 8367365 8370628
* @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed)
* @key randomness
* @library /test/lib
Expand Down Expand Up @@ -232,7 +232,7 @@ public static void pow(int order) {
failCount1++;

failCount1 += checkResult(x.signum() < 0 && power % 2 == 0 ? x.negate() : x,
y.nthRoot(power), "BigInteger.pow() inconsistent with BigInteger.nthRoot()");
y.rootn(power), "BigInteger.pow() inconsistent with BigInteger.rootn()");
}
report("pow for " + order + " bits", failCount1);
}
Expand Down Expand Up @@ -414,18 +414,18 @@ public static void squareRootAndRemainder() {
BigInteger.valueOf(x)).collect(Collectors.summingInt(g)));
}

private static void nthRootSmall() {
private static void rootnSmall() {
int failCount = 0;

// A non-positive degree should cause an exception.
int n = 0;
BigInteger x = BigInteger.ONE;
BigInteger s;
try {
s = x.nthRoot(n);
// If nthRoot() does not throw an exception that is a failure.
s = x.rootn(n);
// If rootn() does not throw an exception that is a failure.
failCount++;
printErr("nthRoot() of non-positive degree did not throw an exception");
printErr("rootn() of non-positive degree did not throw an exception");
} catch (ArithmeticException expected) {
// Not a failure
}
Expand All @@ -434,70 +434,70 @@ private static void nthRootSmall() {
n = 4;
x = BigInteger.valueOf(-1);
try {
s = x.nthRoot(n);
// If nthRoot() does not throw an exception that is a failure.
s = x.rootn(n);
// If rootn() does not throw an exception that is a failure.
failCount++;
printErr("nthRoot() of negative number and even degree did not throw an exception");
printErr("rootn() of negative number and even degree did not throw an exception");
} catch (ArithmeticException expected) {
// Not a failure
}

// A negative value with odd degree should return -nthRoot(-x, n)
// A negative value with odd degree should return -rootn(-x, n)
n = 3;
x = BigInteger.valueOf(-8);
failCount += checkResult(x.negate().nthRoot(n).negate(), x.nthRoot(n),
"nthRoot(" + x + ", " + n + ") != -nthRoot(" + x.negate() + ", " + n + ")");
failCount += checkResult(x.negate().rootn(n).negate(), x.rootn(n),
"rootn(" + x + ", " + n + ") != -rootn(" + x.negate() + ", " + n + ")");

// A zero value should return BigInteger.ZERO.
failCount += checkResult(BigInteger.ZERO, BigInteger.ZERO.nthRoot(n),
"nthRoot(0, " + n + ") != 0");
failCount += checkResult(BigInteger.ZERO, BigInteger.ZERO.rootn(n),
"rootn(0, " + n + ") != 0");

// A one degree should return x.
x = BigInteger.TWO;
failCount += checkResult(x, x.nthRoot(1), "nthRoot(" + x + ", 1) != " + x);
failCount += checkResult(x, x.rootn(1), "rootn(" + x + ", 1) != " + x);

n = 8;
// 1 <= value < 2^n should return BigInteger.ONE.
int end = 1 << n;
for (int i = 1; i < end; i++) {
failCount += checkResult(BigInteger.ONE,
BigInteger.valueOf(i).nthRoot(n), "nthRoot(" + i + ", " + n + ") != 1");
BigInteger.valueOf(i).rootn(n), "rootn(" + i + ", " + n + ") != 1");
}

report("nthRootSmall", failCount);
report("rootnSmall", failCount);
}

public static void nthRoot() {
nthRootSmall();
public static void rootn() {
rootnSmall();

ToIntFunction<BigInteger> f = (x) -> {
int n = random.nextInt(x.bitLength()) + 2;
int failCount = 0;

// nth root of x^n -> x
BigInteger xN = x.pow(n);
failCount += checkResult(x, xN.nthRoot(n), "nthRoot() x^n -> x");
failCount += checkResult(x, xN.rootn(n), "rootn() x^n -> x");

// nth root of x^n + 1 -> x
BigInteger xNup = xN.add(BigInteger.ONE);
failCount += checkResult(x, xNup.nthRoot(n), "nthRoot() x^n + 1 -> x");
failCount += checkResult(x, xNup.rootn(n), "rootn() x^n + 1 -> x");

// nth root of (x + 1)^n - 1 -> x
BigInteger up =
x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE);
failCount += checkResult(x, up.nthRoot(n), "nthRoot() (x + 1)^n - 1 -> x");
failCount += checkResult(x, up.rootn(n), "rootn() (x + 1)^n - 1 -> x");

// nthRoot(x, n)^n <= x
BigInteger r = x.nthRoot(n);
// rootn(x, n)^n <= x
BigInteger r = x.rootn(n);
if (r.pow(n).compareTo(x) > 0) {
failCount++;
printErr("nthRoot(x, n)^n > x for x = " + x + ", n = " + n);
printErr("rootn(x, n)^n > x for x = " + x + ", n = " + n);
}

// (nthRoot(x, n) + 1)^n > x
// (rootn(x, n) + 1)^n > x
if (r.add(BigInteger.ONE).pow(n).compareTo(x) <= 0) {
failCount++;
printErr("(nthRoot(x, n) + 1)^n <= x for x = " + x + ", n = " + n);
printErr("(rootn(x, n) + 1)^n <= x for x = " + x + ", n = " + n);
}

return failCount;
Expand All @@ -513,52 +513,52 @@ public static void nthRoot() {
}
sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger());
sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE));
report("nthRoot for 2^N, 2^N - 1 and 2^N + 1, 1 <= N <= " + maxExponent,
report("rootn for 2^N, 2^N - 1 and 2^N + 1, 1 <= N <= " + maxExponent,
sb.build().collect(Collectors.summingInt(f)));

IntStream ints = random.ints(SIZE, 2, Integer.MAX_VALUE);
report("nthRoot for int", ints.mapToObj(x ->
report("rootn for int", ints.mapToObj(x ->
BigInteger.valueOf(x)).collect(Collectors.summingInt(f)));

LongStream longs = random.longs(SIZE, Integer.MAX_VALUE + 1L, Long.MAX_VALUE);
report("nthRoot for long", longs.mapToObj(x ->
report("rootn for long", longs.mapToObj(x ->
BigInteger.valueOf(x)).collect(Collectors.summingInt(f)));

DoubleStream doubles = random.doubles(SIZE, 0x1p63, Math.scalb(1.0, maxExponent));
report("nthRoot for double", doubles.mapToObj(x ->
report("rootn for double", doubles.mapToObj(x ->
BigDecimal.valueOf(x).toBigInteger()).collect(Collectors.summingInt(f)));
}

public static void nthRootAndRemainder() {
public static void rootnAndRemainder() {
ToIntFunction<BigInteger> g = (x) -> {
int failCount = 0;
int n = random.nextInt(x.bitLength()) + 2;
BigInteger xN = x.pow(n);

// nth root of x^n -> x
BigInteger[] actual = xN.nthRootAndRemainder(n);
failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]");
failCount += checkResult(BigInteger.ZERO, actual[1], "nthRootAndRemainder()[1]");
BigInteger[] actual = xN.rootnAndRemainder(n);
failCount += checkResult(x, actual[0], "rootnAndRemainder()[0]");
failCount += checkResult(BigInteger.ZERO, actual[1], "rootnAndRemainder()[1]");

// nth root of x^n + 1 -> x
BigInteger xNup = xN.add(BigInteger.ONE);
actual = xNup.nthRootAndRemainder(n);
failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]");
failCount += checkResult(BigInteger.ONE, actual[1], "nthRootAndRemainder()[1]");
actual = xNup.rootnAndRemainder(n);
failCount += checkResult(x, actual[0], "rootnAndRemainder()[0]");
failCount += checkResult(BigInteger.ONE, actual[1], "rootnAndRemainder()[1]");

// nth root of (x + 1)^n - 1 -> x
BigInteger up =
x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE);
actual = up.nthRootAndRemainder(n);
failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]");
actual = up.rootnAndRemainder(n);
failCount += checkResult(x, actual[0], "rootnAndRemainder()[0]");
BigInteger r = up.subtract(xN);
failCount += checkResult(r, actual[1], "nthRootAndRemainder()[1]");
failCount += checkResult(r, actual[1], "rootnAndRemainder()[1]");

return failCount;
};

IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE);
report("nthRootAndRemainder", bits.mapToObj(x ->
report("rootnAndRemainder", bits.mapToObj(x ->
BigInteger.valueOf(x)).collect(Collectors.summingInt(g)));
}

Expand Down Expand Up @@ -1472,8 +1472,8 @@ public static void main(String[] args) throws Exception {
squareRoot();
squareRootAndRemainder();

nthRoot();
nthRootAndRemainder();
rootn();
rootnAndRemainder();
}

if (failure)
Expand Down