1 /*
2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package test.java.math.BigDecimal;
24 
25 /*
26  * @test
27  * @bug 4851776 4907265 6177836 6876282 8066842
28  * @summary Some tests for the divide methods.
29  * @author Joseph D. Darcy
30  */
31 
32 import java.math.*;
33 import static java.math.BigDecimal.*;
34 
35 import org.testng.Assert;
36 import org.testng.annotations.Test;
37 
38 // Android-changed: Replace error counting with asserts.
39 public class DivideTests {
40 
41     // Preliminary exact divide method; could be used for comparison
42     // purposes.
anotherDivide(BigDecimal dividend, BigDecimal divisor)43     BigDecimal anotherDivide(BigDecimal dividend, BigDecimal divisor) {
44         /*
45          * Handle zero cases first.
46          */
47         if (divisor.signum() == 0) {   // x/0
48             if (dividend.signum() == 0)    // 0/0
49                 throw new ArithmeticException("Division undefined");  // NaN
50             throw new ArithmeticException("Division by zero");
51         }
52         if (dividend.signum() == 0)        // 0/y
53             return BigDecimal.ZERO;
54         else {
55             /*
56              * Determine if there is a result with a terminating
57              * decimal expansion.  Putting aside overflow and
58              * underflow considerations, the existance of an exact
59              * result only depends on the ratio of the intVal's of the
60              * dividend (i.e. this) and and divisor since the scales
61              * of the argument just affect where the decimal point
62              * lies.
63              *
64              * For the ratio of (a = this.intVal) and (b =
65              * divisor.intVal) to have a finite decimal expansion,
66              * once a/b is put in lowest terms, b must be equal to
67              * (2^i)*(5^j) for some integer i,j >= 0.  Therefore, we
68              * first compute to see if b_prime =(b/gcd(a,b)) is equal
69              * to (2^i)*(5^j).
70              */
71             BigInteger TWO  = BigInteger.valueOf(2);
72             BigInteger FIVE = BigInteger.valueOf(5);
73             BigInteger TEN  = BigInteger.valueOf(10);
74 
75             BigInteger divisorIntvalue  = divisor.scaleByPowerOfTen(divisor.scale()).toBigInteger().abs();
76             BigInteger dividendIntvalue = dividend.scaleByPowerOfTen(dividend.scale()).toBigInteger().abs();
77 
78             BigInteger b_prime = divisorIntvalue.divide(dividendIntvalue.gcd(divisorIntvalue));
79 
80             boolean goodDivisor = false;
81             int i=0, j=0;
82 
83             badDivisor: {
84                 while(! b_prime.equals(BigInteger.ONE) ) {
85                     int b_primeModTen = b_prime.mod(TEN).intValue() ;
86 
87                     switch(b_primeModTen) {
88                     case 0:
89                         // b_prime divisible by 10=2*5, increment i and j
90                         i++;
91                         j++;
92                         b_prime = b_prime.divide(TEN);
93                         break;
94 
95                     case 5:
96                         // b_prime divisible by 5, increment j
97                         j++;
98                         b_prime = b_prime.divide(FIVE);
99                         break;
100 
101                     case 2:
102                     case 4:
103                     case 6:
104                     case 8:
105                         // b_prime divisible by 2, increment i
106                         i++;
107                         b_prime = b_prime.divide(TWO);
108                         break;
109 
110                     default: // hit something we shouldn't have
111                         b_prime = BigInteger.ONE; // terminate loop
112                         break badDivisor;
113                     }
114                 }
115 
116                 goodDivisor = true;
117             }
118 
119             if( ! goodDivisor ) {
120                 throw new ArithmeticException("Non terminating decimal expansion");
121             }
122             else {
123                 // What is a rule for determining how many digits are
124                 // needed?  Once that is determined, cons up a new
125                 // MathContext object and pass it on to the divide(bd,
126                 // mc) method; precision == ?, roundingMode is unnecessary.
127 
128                 // Are we sure this is the right scale to use?  Should
129                 // also determine a precision-based method.
130                 MathContext mc = new MathContext(dividend.precision() +
131                                                  (int)Math.ceil(
132                                                       10.0*divisor.precision()/3.0),
133                                                  RoundingMode.UNNECESSARY);
134                 // Should do some more work here to rescale, etc.
135                 return dividend.divide(divisor, mc);
136             }
137         }
138     }
139 
140     @Test
powersOf2and5()141     public void powersOf2and5() {
142         for(int i = 0; i < 6; i++) {
143             int powerOf2 = (int)StrictMath.pow(2.0, i);
144 
145             for(int j = 0; j < 6; j++) {
146                 int powerOf5 = (int)StrictMath.pow(5.0, j);
147                 int product;
148 
149                 BigDecimal bd;
150 
151                 try {
152                     bd = BigDecimal.ONE.divide(new BigDecimal(product=powerOf2*powerOf5));
153                 } catch (ArithmeticException e) {
154                     Assert.fail((new BigDecimal(powerOf2)).toString() + " / " +
155                                        (new BigDecimal(powerOf5)).toString() + " threw an exception.");
156                 }
157 
158                 try {
159                     bd = new BigDecimal(powerOf2).divide(new BigDecimal(powerOf5));
160                 } catch (ArithmeticException e) {
161                     Assert.fail((new BigDecimal(powerOf2)).toString() + " / " +
162                                        (new BigDecimal(powerOf5)).toString() + " threw an exception.");
163                 }
164 
165                 try {
166                     bd = new BigDecimal(powerOf5).divide(new BigDecimal(powerOf2));
167                 } catch (ArithmeticException e) {
168                     Assert.fail((new BigDecimal(powerOf5)).toString() + " / " +
169                                        (new BigDecimal(powerOf2)).toString() + " threw an exception.");
170                 }
171 
172             }
173         }
174     }
175 
176     @Test
nonTerminating()177     public void nonTerminating() {
178         int[] primes = {1, 3, 7, 13, 17};
179 
180         // For each pair of prime products, verify the ratio of
181         // non-equal products has a non-terminating expansion.
182 
183         for(int i = 0; i < primes.length; i++) {
184             for(int j = i+1; j < primes.length; j++) {
185 
186                 for(int m = 0; m < primes.length; m++) {
187                     for(int n = m+1; n < primes.length; n++) {
188                         int dividend = primes[i] * primes[j];
189                         int divisor  = primes[m] * primes[n];
190 
191                         if ( ((dividend/divisor) * divisor) != dividend ) {
192                             try {
193                                 BigDecimal quotient = (new BigDecimal(dividend).
194                                                        divide(new BigDecimal(divisor)));
195                                 Assert.fail("Exact quotient " + quotient.toString() +
196                                                    " returned for non-terminating fraction " +
197                                                    dividend + " / " + divisor + ".");
198                             }
199                             catch (ArithmeticException e) {
200                                 ; // Correct result
201                             }
202                         }
203 
204                     }
205                 }
206             }
207         }
208     }
209 
210     @Test
properScaleTests()211     public void properScaleTests(){
212         BigDecimal[][] testCases = {
213             {new BigDecimal("1"),       new BigDecimal("5"),            new BigDecimal("2e-1")},
214             {new BigDecimal("1"),       new BigDecimal("50e-1"),        new BigDecimal("2e-1")},
215             {new BigDecimal("10e-1"),   new BigDecimal("5"),            new BigDecimal("2e-1")},
216             {new BigDecimal("1"),       new BigDecimal("500e-2"),       new BigDecimal("2e-1")},
217             {new BigDecimal("100e-2"),  new BigDecimal("5"),            new BigDecimal("20e-2")},
218             {new BigDecimal("1"),       new BigDecimal("32"),           new BigDecimal("3125e-5")},
219             {new BigDecimal("1"),       new BigDecimal("64"),           new BigDecimal("15625e-6")},
220             {new BigDecimal("1.0000000"),       new BigDecimal("64"),   new BigDecimal("156250e-7")},
221         };
222 
223 
224         for(BigDecimal[] tc : testCases) {
225             BigDecimal quotient = tc[0].divide(tc[1]);
226             Assert.assertEquals(quotient, tc[2],
227                 "Unexpected quotient from " + tc[0] + " / " + tc[1] +
228                                    "; expected " + tc[2] + " got " + quotient);
229         }
230     }
231 
232     @Test
trailingZeroTests()233     public void trailingZeroTests() {
234         MathContext mc = new MathContext(3, RoundingMode.FLOOR);
235         BigDecimal[][] testCases = {
236             {new BigDecimal("19"),      new BigDecimal("100"),          new BigDecimal("0.19")},
237             {new BigDecimal("21"),      new BigDecimal("110"),          new BigDecimal("0.190")},
238         };
239 
240         for(BigDecimal[] tc : testCases) {
241             BigDecimal quotient = tc[0].divide(tc[1], mc);
242             Assert.assertEquals(quotient, tc[2],
243                 "Unexpected quotient from " + tc[0] + " / " + tc[1] +
244                                    "; expected " + tc[2] + " got " + quotient);
245         }
246     }
247 
248     @Test
scaledRoundedDivideTests()249     public void scaledRoundedDivideTests() {
250         // Tests of the traditional scaled divide under different
251         // rounding modes.
252 
253         // Encode rounding mode and scale for the divide in a
254         // BigDecimal with the significand equal to the rounding mode
255         // and the scale equal to the number's scale.
256 
257         // {dividend, divisor, rounding, quotient}
258         BigDecimal a = new BigDecimal("31415");
259         BigDecimal a_minus = a.negate();
260         BigDecimal b = new BigDecimal("10000");
261 
262         BigDecimal c = new BigDecimal("31425");
263         BigDecimal c_minus = c.negate();
264 
265          // Ad hoc tests
266         BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);
267         BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);
268 
269         BigDecimal[][] testCases = {
270             {a,         b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("3.142")},
271             {a_minus,   b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("-3.142")},
272 
273             {a,         b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("3.141")},
274             {a_minus,   b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("-3.141")},
275 
276             {a,         b,      BigDecimal.valueOf(ROUND_CEILING, 3),   new BigDecimal("3.142")},
277             {a_minus,   b,      BigDecimal.valueOf(ROUND_CEILING, 3),   new BigDecimal("-3.141")},
278 
279             {a,         b,      BigDecimal.valueOf(ROUND_FLOOR, 3),     new BigDecimal("3.141")},
280             {a_minus,   b,      BigDecimal.valueOf(ROUND_FLOOR, 3),     new BigDecimal("-3.142")},
281 
282             {a,         b,      BigDecimal.valueOf(ROUND_HALF_UP, 3),   new BigDecimal("3.142")},
283             {a_minus,   b,      BigDecimal.valueOf(ROUND_HALF_UP, 3),   new BigDecimal("-3.142")},
284 
285             {a,         b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("3.141")},
286             {a_minus,   b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("-3.141")},
287 
288             {a,         b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
289             {a_minus,   b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
290 
291             {c,         b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
292             {c_minus,   b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
293 
294             {d,         e,      BigDecimal.valueOf(ROUND_HALF_UP, -5),   BigDecimal.valueOf(-1, -5)},
295             {d,         e,      BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},
296             {d,         e,      BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},
297         };
298 
299         for(BigDecimal[] tc : testCases) {
300             int scale = tc[2].scale();
301             int rm = tc[2].unscaledValue().intValue();
302 
303             BigDecimal quotient = tc[0].divide(tc[1], scale, rm);
304             Assert.assertEquals(quotient, tc[3],
305                 "Unexpected quotient from " + tc[0] + " / " + tc[1] +
306                                    " scale " + scale + " rounding mode " + RoundingMode.valueOf(rm) +
307                                    "; expected " + tc[3] + " got " + quotient);
308         }
309 
310         // 6876282
311         BigDecimal[][] testCases2 = {
312             // { dividend, divisor, expected quotient }
313             { new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },
314             { new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),
315               new BigDecimal(441) },
316             { new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),
317               new BigDecimal("0.000115309916") },
318             { new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),
319               new BigDecimal(4) },
320             { new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),
321               new BigDecimal(4) },
322             { new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),
323               new BigDecimal(5) },
324             { new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),
325               new BigDecimal(4) },
326             { new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),
327               new BigDecimal(4) },
328         };
329 
330         for (BigDecimal[] test : testCases2) {
331             BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);
332             Assert.assertEquals(quo, test[2], "Unexpected quotient from " + test[0] + " / " + test[1] +
333                                    " rounding mode HALF_UP" +
334                                    "; expected " + test[2] + " got " + quo);
335         }
336     }
337 
338     @Test
divideByOneTests()339     public void divideByOneTests() {
340         //problematic divisor: one with scale 17
341         BigDecimal one = BigDecimal.ONE.setScale(17);
342         RoundingMode rounding = RoundingMode.UNNECESSARY;
343 
344         long[][] unscaledAndScale = new long[][] {
345             { Long.MAX_VALUE,  17},
346             {-Long.MAX_VALUE,  17},
347             { Long.MAX_VALUE,   0},
348             {-Long.MAX_VALUE,   0},
349             { Long.MAX_VALUE, 100},
350             {-Long.MAX_VALUE, 100}
351         };
352 
353         for (long[] uas : unscaledAndScale) {
354             long unscaled = uas[0];
355             int scale = (int)uas[1];
356 
357             BigDecimal noRound = null;
358             try {
359                 noRound = BigDecimal.valueOf(unscaled, scale).
360                     divide(one, RoundingMode.UNNECESSARY);
361             } catch (ArithmeticException e) {
362                 Assert.fail("ArithmeticException for value " + unscaled
363                     + " and scale " + scale + " without rounding");
364             }
365 
366             BigDecimal roundDown = null;
367             try {
368                 roundDown = BigDecimal.valueOf(unscaled, scale).
369                         divide(one, RoundingMode.DOWN);
370             } catch (ArithmeticException e) {
371                 Assert.fail("ArithmeticException for value " + unscaled
372                     + " and scale " + scale + " with rounding down");
373             }
374 
375             if (noRound != null && roundDown != null && noRound.compareTo(roundDown) != 0) {
376                 Assert.fail("Equality failure for value " + unscaled
377                         + " and scale " + scale);
378             }
379         }
380     }
381 }
382