Skip to content

Commit

Permalink
NUMBERS-150: Fix Fraction.pow and BigFraction.pow
Browse files Browse the repository at this point in the history
Modified to:

- correctly handle Integer.MIN_VALUE as the argument.
- throw an ArithmeticException when zero is raised to a negative power.

Squashed commit of the following:

commit 0fd1da5
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 04:36:46 2020 +0800

    fix checkstyles

commit 4c2aa76
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 04:34:54 2020 +0800

    apply suggestions

commit 0fc3a52
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 04:27:42 2020 +0800

    apply suggestions

commit 1481998
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 04:24:58 2020 +0800

    apply suggestions

commit 4467842
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:28:58 2020 +0800

    fix checkstyles

commit 708414c
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:27:43 2020 +0800

    change as suggested

commit 5b9c91a
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:24:56 2020 +0800

    change as suggested

commit 12142b6
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:23:57 2020 +0800

    change as suggested

commit 3f10f12
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:22:13 2020 +0800

    change as suggested

commit d01b5b8
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:20:50 2020 +0800

    change as suggested

commit 6f23df0
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:16:33 2020 +0800

    change as suggested

commit 3646e00
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:15:10 2020 +0800

    change as suggested

commit 3d4bc49
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:13:29 2020 +0800

    change as suggested

commit 267df94
Author: XenoAmess <[email protected]>
Date:   Wed Aug 26 03:12:04 2020 +0800

    change as suggested

commit ba0d39b
Author: XenoAmess <[email protected]>
Date:   Tue Aug 25 21:26:27 2020 +0800

    [NUMBERS-150] fix bug in Fraction.pow and BigFraction.pow
  • Loading branch information
aherbert committed Aug 25, 2020
1 parent 3282fb8 commit a8897d1
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -966,23 +966,36 @@ public BigFraction divide(final BigFraction value) {
*/
@Override
public BigFraction pow(final int exponent) {
if (exponent == 1) {
return this;
}
if (exponent == 0) {
return ONE;
}
if (isZero()) {
if (exponent < 0) {
throw new FractionException(FractionException.ERROR_ZERO_DENOMINATOR);
}
return ZERO;
}

if (exponent > 0) {
return new BigFraction(numerator.pow(exponent),
denominator.pow(exponent));
}
if (exponent == -1) {
return this.reciprocal();
}
if (exponent == Integer.MIN_VALUE) {
// MIN_VALUE can't be negated
return new BigFraction(denominator.pow(Integer.MAX_VALUE).multiply(denominator),
numerator.pow(Integer.MAX_VALUE).multiply(numerator));
}
// Note: Raise the BigIntegers to the power and then reduce.
// The supported range for BigInteger is currently
// +/-2^(Integer.MAX_VALUE) exclusive thus larger
// exponents (long, BigInteger) are currently not supported.
if (exponent < 0) {
return new BigFraction(denominator.pow(-exponent),
numerator.pow(-exponent));
}
return new BigFraction(numerator.pow(exponent),
denominator.pow(exponent));
return new BigFraction(denominator.pow(-exponent),
numerator.pow(-exponent));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -775,19 +775,32 @@ public Fraction divide(Fraction value) {
*/
@Override
public Fraction pow(final int exponent) {
if (exponent == 1) {
return this;
}
if (exponent == 0) {
return ONE;
}
if (isZero()) {
if (exponent < 0) {
throw new FractionException(FractionException.ERROR_ZERO_DENOMINATOR);
}
return ZERO;
}

if (exponent < 0) {
return new Fraction(ArithmeticUtils.pow(denominator, -exponent),
ArithmeticUtils.pow(numerator, -exponent));
if (exponent > 0) {
return new Fraction(ArithmeticUtils.pow(numerator, exponent),
ArithmeticUtils.pow(denominator, exponent));
}
if (exponent == -1) {
return this.reciprocal();
}
if (exponent == Integer.MIN_VALUE) {
// MIN_VALUE can't be negated
return new Fraction(ArithmeticUtils.pow(denominator, Integer.MAX_VALUE) * denominator,
ArithmeticUtils.pow(numerator, Integer.MAX_VALUE) * numerator);
}
return new Fraction(ArithmeticUtils.pow(numerator, exponent),
ArithmeticUtils.pow(denominator, exponent));
return new Fraction(ArithmeticUtils.pow(denominator, -exponent),
ArithmeticUtils.pow(numerator, -exponent));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -778,4 +778,15 @@ void testMath340() {
fractionA.getDenominator().multiply(fractionB.getDenominator()));
Assertions.assertEquals(correctResult, errorResult);
}

@Test
void testNumbers150() {
// zero to negative powers should throw an exception
Assertions.assertThrows(ArithmeticException.class, () -> BigFraction.ZERO.pow(-1));
Assertions.assertThrows(ArithmeticException.class, () -> BigFraction.ZERO.pow(Integer.MIN_VALUE));

// shall overflow
Assertions.assertThrows(ArithmeticException.class, () -> BigFraction.of(2).pow(Integer.MIN_VALUE));
Assertions.assertThrows(ArithmeticException.class, () -> BigFraction.of(1, 2).pow(Integer.MIN_VALUE));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,10 @@ private static List<BinaryIntOperatorTestCase> collectPowTestCases() {
testCases.add(new BinaryIntOperatorTestCase(0, 1, Integer.MAX_VALUE, 0, 1));
testCases.add(new BinaryIntOperatorTestCase(0, -1, Integer.MAX_VALUE, 0, 1));

testCases.add(new BinaryIntOperatorTestCase(1, 1, Integer.MIN_VALUE, 1, 1));
testCases.add(new BinaryIntOperatorTestCase(1, -1, Integer.MIN_VALUE, 1, 1));
testCases.add(new BinaryIntOperatorTestCase(-1, 1, Integer.MIN_VALUE, 1, 1));
testCases.add(new BinaryIntOperatorTestCase(-1, -1, Integer.MIN_VALUE, 1, 1));
return testCases;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,17 @@ void testMath1261() {
assertFraction(1, Integer.MAX_VALUE, b.divide(2));
}

@Test
void testNumbers150() {
// zero to negative powers should throw an exception
Assertions.assertThrows(ArithmeticException.class, () -> Fraction.ZERO.pow(-1));
Assertions.assertThrows(ArithmeticException.class, () -> Fraction.ZERO.pow(Integer.MIN_VALUE));

// shall overflow
Assertions.assertThrows(ArithmeticException.class, () -> Fraction.of(2).pow(Integer.MIN_VALUE));
Assertions.assertThrows(ArithmeticException.class, () -> Fraction.of(1, 2).pow(Integer.MIN_VALUE));
}

/**
* Defines test cases that cause overflow in {@link Fraction#add(Fraction)}.
* @return a list of test cases
Expand Down

0 comments on commit a8897d1

Please sign in to comment.