Path: blob/master/test/jdk/java/math/BigDecimal/DivideTests.java
41149 views
/*1* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 4851776 4907265 6177836 6876282 806684226* @summary Some tests for the divide methods.27* @author Joseph D. Darcy28*/2930import java.math.*;31import static java.math.BigDecimal.*;3233public class DivideTests {3435// Preliminary exact divide method; could be used for comparison36// purposes.37BigDecimal anotherDivide(BigDecimal dividend, BigDecimal divisor) {38/*39* Handle zero cases first.40*/41if (divisor.signum() == 0) { // x/042if (dividend.signum() == 0) // 0/043throw new ArithmeticException("Division undefined"); // NaN44throw new ArithmeticException("Division by zero");45}46if (dividend.signum() == 0) // 0/y47return BigDecimal.ZERO;48else {49/*50* Determine if there is a result with a terminating51* decimal expansion. Putting aside overflow and52* underflow considerations, the existance of an exact53* result only depends on the ratio of the intVal's of the54* dividend (i.e. this) and and divisor since the scales55* of the argument just affect where the decimal point56* lies.57*58* For the ratio of (a = this.intVal) and (b =59* divisor.intVal) to have a finite decimal expansion,60* once a/b is put in lowest terms, b must be equal to61* (2^i)*(5^j) for some integer i,j >= 0. Therefore, we62* first compute to see if b_prime =(b/gcd(a,b)) is equal63* to (2^i)*(5^j).64*/65BigInteger TWO = BigInteger.valueOf(2);66BigInteger FIVE = BigInteger.valueOf(5);67BigInteger TEN = BigInteger.valueOf(10);6869BigInteger divisorIntvalue = divisor.scaleByPowerOfTen(divisor.scale()).toBigInteger().abs();70BigInteger dividendIntvalue = dividend.scaleByPowerOfTen(dividend.scale()).toBigInteger().abs();7172BigInteger b_prime = divisorIntvalue.divide(dividendIntvalue.gcd(divisorIntvalue));7374boolean goodDivisor = false;75int i=0, j=0;7677badDivisor: {78while(! b_prime.equals(BigInteger.ONE) ) {79int b_primeModTen = b_prime.mod(TEN).intValue() ;8081switch(b_primeModTen) {82case 0:83// b_prime divisible by 10=2*5, increment i and j84i++;85j++;86b_prime = b_prime.divide(TEN);87break;8889case 5:90// b_prime divisible by 5, increment j91j++;92b_prime = b_prime.divide(FIVE);93break;9495case 2:96case 4:97case 6:98case 8:99// b_prime divisible by 2, increment i100i++;101b_prime = b_prime.divide(TWO);102break;103104default: // hit something we shouldn't have105b_prime = BigInteger.ONE; // terminate loop106break badDivisor;107}108}109110goodDivisor = true;111}112113if( ! goodDivisor ) {114throw new ArithmeticException("Non terminating decimal expansion");115}116else {117// What is a rule for determining how many digits are118// needed? Once that is determined, cons up a new119// MathContext object and pass it on to the divide(bd,120// mc) method; precision == ?, roundingMode is unnecessary.121122// Are we sure this is the right scale to use? Should123// also determine a precision-based method.124MathContext mc = new MathContext(dividend.precision() +125(int)Math.ceil(12610.0*divisor.precision()/3.0),127RoundingMode.UNNECESSARY);128// Should do some more work here to rescale, etc.129return dividend.divide(divisor, mc);130}131}132}133134public static int powersOf2and5() {135int failures = 0;136137for(int i = 0; i < 6; i++) {138int powerOf2 = (int)StrictMath.pow(2.0, i);139140for(int j = 0; j < 6; j++) {141int powerOf5 = (int)StrictMath.pow(5.0, j);142int product;143144BigDecimal bd;145146try {147bd = BigDecimal.ONE.divide(new BigDecimal(product=powerOf2*powerOf5));148} catch (ArithmeticException e) {149failures++;150System.err.println((new BigDecimal(powerOf2)).toString() + " / " +151(new BigDecimal(powerOf5)).toString() + " threw an exception.");152e.printStackTrace();153}154155try {156bd = new BigDecimal(powerOf2).divide(new BigDecimal(powerOf5));157} catch (ArithmeticException e) {158failures++;159System.err.println((new BigDecimal(powerOf2)).toString() + " / " +160(new BigDecimal(powerOf5)).toString() + " threw an exception.");161e.printStackTrace();162}163164try {165bd = new BigDecimal(powerOf5).divide(new BigDecimal(powerOf2));166} catch (ArithmeticException e) {167failures++;168System.err.println((new BigDecimal(powerOf5)).toString() + " / " +169(new BigDecimal(powerOf2)).toString() + " threw an exception.");170171e.printStackTrace();172}173174}175}176return failures;177}178179public static int nonTerminating() {180int failures = 0;181int[] primes = {1, 3, 7, 13, 17};182183// For each pair of prime products, verify the ratio of184// non-equal products has a non-terminating expansion.185186for(int i = 0; i < primes.length; i++) {187for(int j = i+1; j < primes.length; j++) {188189for(int m = 0; m < primes.length; m++) {190for(int n = m+1; n < primes.length; n++) {191int dividend = primes[i] * primes[j];192int divisor = primes[m] * primes[n];193194if ( ((dividend/divisor) * divisor) != dividend ) {195try {196BigDecimal quotient = (new BigDecimal(dividend).197divide(new BigDecimal(divisor)));198failures++;199System.err.println("Exact quotient " + quotient.toString() +200" returned for non-terminating fraction " +201dividend + " / " + divisor + ".");202}203catch (ArithmeticException e) {204; // Correct result205}206}207208}209}210}211}212213return failures;214}215216public static int properScaleTests(){217int failures = 0;218219BigDecimal[][] testCases = {220{new BigDecimal("1"), new BigDecimal("5"), new BigDecimal("2e-1")},221{new BigDecimal("1"), new BigDecimal("50e-1"), new BigDecimal("2e-1")},222{new BigDecimal("10e-1"), new BigDecimal("5"), new BigDecimal("2e-1")},223{new BigDecimal("1"), new BigDecimal("500e-2"), new BigDecimal("2e-1")},224{new BigDecimal("100e-2"), new BigDecimal("5"), new BigDecimal("20e-2")},225{new BigDecimal("1"), new BigDecimal("32"), new BigDecimal("3125e-5")},226{new BigDecimal("1"), new BigDecimal("64"), new BigDecimal("15625e-6")},227{new BigDecimal("1.0000000"), new BigDecimal("64"), new BigDecimal("156250e-7")},228};229230231for(BigDecimal[] tc : testCases) {232BigDecimal quotient;233if (! (quotient = tc[0].divide(tc[1])).equals(tc[2]) ) {234failures++;235System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +236"; expected " + tc[2] + " got " + quotient);237}238}239240return failures;241}242243public static int trailingZeroTests() {244int failures = 0;245246MathContext mc = new MathContext(3, RoundingMode.FLOOR);247BigDecimal[][] testCases = {248{new BigDecimal("19"), new BigDecimal("100"), new BigDecimal("0.19")},249{new BigDecimal("21"), new BigDecimal("110"), new BigDecimal("0.190")},250};251252for(BigDecimal[] tc : testCases) {253BigDecimal quotient;254if (! (quotient = tc[0].divide(tc[1], mc)).equals(tc[2]) ) {255failures++;256System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +257"; expected " + tc[2] + " got " + quotient);258}259}260261return failures;262}263264public static int scaledRoundedDivideTests() {265int failures = 0;266// Tests of the traditional scaled divide under different267// rounding modes.268269// Encode rounding mode and scale for the divide in a270// BigDecimal with the significand equal to the rounding mode271// and the scale equal to the number's scale.272273// {dividend, dividisor, rounding, quotient}274BigDecimal a = new BigDecimal("31415");275BigDecimal a_minus = a.negate();276BigDecimal b = new BigDecimal("10000");277278BigDecimal c = new BigDecimal("31425");279BigDecimal c_minus = c.negate();280281// Ad hoc tests282BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);283BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);284285BigDecimal[][] testCases = {286{a, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("3.142")},287{a_minus, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("-3.142")},288289{a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},290{a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},291292{a, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("3.142")},293{a_minus, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("-3.141")},294295{a, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("3.141")},296{a_minus, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("-3.142")},297298{a, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("3.142")},299{a_minus, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("-3.142")},300301{a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},302{a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},303304{a, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},305{a_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},306307{c, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},308{c_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},309310{d, e, BigDecimal.valueOf(ROUND_HALF_UP, -5), BigDecimal.valueOf(-1, -5)},311{d, e, BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},312{d, e, BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},313};314315for(BigDecimal tc[] : testCases) {316int scale = tc[2].scale();317int rm = tc[2].unscaledValue().intValue();318319BigDecimal quotient = tc[0].divide(tc[1], scale, rm);320if (!quotient.equals(tc[3])) {321failures++;322System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +323" scale " + scale + " rounding mode " + RoundingMode.valueOf(rm) +324"; expected " + tc[3] + " got " + quotient);325}326}327328// 6876282329BigDecimal[][] testCases2 = {330// { dividend, divisor, expected quotient }331{ new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },332{ new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),333new BigDecimal(441) },334{ new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),335new BigDecimal("0.000115309916") },336{ new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),337new BigDecimal(4) },338{ new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),339new BigDecimal(4) },340{ new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),341new BigDecimal(5) },342{ new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),343new BigDecimal(4) },344{ new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),345new BigDecimal(4) },346};347348for (BigDecimal test[] : testCases2) {349BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);350if (!quo.equals(test[2])) {351failures++;352System.err.println("Unexpected quotient from " + test[0] + " / " + test[1] +353" rounding mode HALF_UP" +354"; expected " + test[2] + " got " + quo);355}356}357return failures;358}359360private static int divideByOneTests() {361int failures = 0;362363//problematic divisor: one with scale 17364BigDecimal one = BigDecimal.ONE.setScale(17);365RoundingMode rounding = RoundingMode.UNNECESSARY;366367long[][] unscaledAndScale = new long[][] {368{ Long.MAX_VALUE, 17},369{-Long.MAX_VALUE, 17},370{ Long.MAX_VALUE, 0},371{-Long.MAX_VALUE, 0},372{ Long.MAX_VALUE, 100},373{-Long.MAX_VALUE, 100}374};375376for (long[] uas : unscaledAndScale) {377long unscaled = uas[0];378int scale = (int)uas[1];379380BigDecimal noRound = null;381try {382noRound = BigDecimal.valueOf(unscaled, scale).383divide(one, RoundingMode.UNNECESSARY);384} catch (ArithmeticException e) {385failures++;386System.err.println("ArithmeticException for value " + unscaled387+ " and scale " + scale + " without rounding");388}389390BigDecimal roundDown = null;391try {392roundDown = BigDecimal.valueOf(unscaled, scale).393divide(one, RoundingMode.DOWN);394} catch (ArithmeticException e) {395failures++;396System.err.println("ArithmeticException for value " + unscaled397+ " and scale " + scale + " with rounding down");398}399400if (noRound != null && roundDown != null401&& noRound.compareTo(roundDown) != 0) {402failures++;403System.err.println("Equality failure for value " + unscaled404+ " and scale " + scale);405}406}407408return failures;409}410411public static void main(String argv[]) {412int failures = 0;413414failures += powersOf2and5();415failures += nonTerminating();416failures += properScaleTests();417failures += trailingZeroTests();418failures += scaledRoundedDivideTests();419failures += divideByOneTests();420421if (failures > 0) {422throw new RuntimeException("Incurred " + failures +423" failures while testing division.");424}425}426}427428429