```   1 /*
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
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  *
20  * CA 95054 USA or visit www.sun.com if you need additional information or
21  * have any questions.
22  */
23
24 /*
25  * @test
26  * @bug 4851776 4907265 6177836
27  * @summary Some tests for the divide methods.
28  * @author Joseph D. Darcy
29  * @compile -source 1.5 DivideTests.java
30  * @run main DivideTests
31  */
32
33 import java.math.*;
34 import static java.math.BigDecimal.*;
35
36 public class DivideTests {
37
38     // Preliminary exact divide method; could be used for comparison
39     // purposes.
40     BigDecimal anotherDivide(BigDecimal dividend, BigDecimal divisor) {
41         /*
42          * Handle zero cases first.
43          */
44         if (divisor.signum() == 0) {   // x/0
45             if (dividend.signum() == 0)    // 0/0
46                 throw new ArithmeticException("Division undefined");  // NaN
47             throw new ArithmeticException("Division by zero");
48         }
49         if (dividend.signum() == 0)        // 0/y
50             return BigDecimal.ZERO;
51         else {
52             /*
53              * Determine if there is a result with a terminating
54              * decimal expansion.  Putting aside overflow and
55              * underflow considerations, the existance of an exact
56              * result only depends on the ratio of the intVal's of the
57              * dividend (i.e. this) and and divisor since the scales
58              * of the argument just affect where the decimal point
59              * lies.
60              *
61              * For the ratio of (a = this.intVal) and (b =
62              * divisor.intVal) to have a finite decimal expansion,
63              * once a/b is put in lowest terms, b must be equal to
64              * (2^i)*(5^j) for some integer i,j >= 0.  Therefore, we
65              * first compute to see if b_prime =(b/gcd(a,b)) is equal
66              * to (2^i)*(5^j).
67              */
68             BigInteger TWO  = BigInteger.valueOf(2);
69             BigInteger FIVE = BigInteger.valueOf(5);
70             BigInteger TEN  = BigInteger.valueOf(10);
71
72             BigInteger divisorIntvalue  = divisor.scaleByPowerOfTen(divisor.scale()).toBigInteger().abs();
73             BigInteger dividendIntvalue = dividend.scaleByPowerOfTen(dividend.scale()).toBigInteger().abs();
74
75             BigInteger b_prime = divisorIntvalue.divide(dividendIntvalue.gcd(divisorIntvalue));
76
77             boolean goodDivisor = false;
78             int i=0, j=0;
79
81                 while(! b_prime.equals(BigInteger.ONE) ) {
82                     int b_primeModTen = b_prime.mod(TEN).intValue() ;
83
84                     switch(b_primeModTen) {
85                     case 0:
86                         // b_prime divisible by 10=2*5, increment i and j
87                         i++;
88                         j++;
89                         b_prime = b_prime.divide(TEN);
90                         break;
91
92                     case 5:
93                         // b_prime divisible by 5, increment j
94                         j++;
95                         b_prime = b_prime.divide(FIVE);
96                         break;
97
98                     case 2:
99                     case 4:
100                     case 6:
101                     case 8:
102                         // b_prime divisible by 2, increment i
103                         i++;
104                         b_prime = b_prime.divide(TWO);
105                         break;
106
107                     default: // hit something we shouldn't have
108                         b_prime = BigInteger.ONE; // terminate loop
110                     }
111                 }
112
113                 goodDivisor = true;
114             }
115
116             if( ! goodDivisor ) {
117                 throw new ArithmeticException("Non terminating decimal expansion");
118             }
119             else {
120                 // What is a rule for determining how many digits are
121                 // needed?  Once that is determined, cons up a new
122                 // MathContext object and pass it on to the divide(bd,
123                 // mc) method; precision == ?, roundingMode is unnecessary.
124
125                 // Are we sure this is the right scale to use?  Should
126                 // also determine a precision-based method.
127                 MathContext mc = new MathContext(dividend.precision() +
128                                                  (int)Math.ceil(
129                                                       10.0*divisor.precision()/3.0),
130                                                  RoundingMode.UNNECESSARY);
131                 // Should do some more work here to rescale, etc.
132                 return dividend.divide(divisor, mc);
133             }
134         }
135     }
136
137     public static int powersOf2and5() {
138         int failures = 0;
139
140         for(int i = 0; i < 6; i++) {
141             int powerOf2 = (int)StrictMath.pow(2.0, i);
142
143             for(int j = 0; j < 6; j++) {
144                 int powerOf5 = (int)StrictMath.pow(5.0, j);
145                 int product;
146
147                 BigDecimal bd;
148
149                 try {
150                     bd = BigDecimal.ONE.divide(new BigDecimal(product=powerOf2*powerOf5));
151                 } catch (ArithmeticException e) {
152                     failures++;
153                     System.err.println((new BigDecimal(powerOf2)).toString() + " / " +
154                                        (new BigDecimal(powerOf5)).toString() + " threw an exception.");
155                     e.printStackTrace();
156                 }
157
158                 try {
159                     bd = new BigDecimal(powerOf2).divide(new BigDecimal(powerOf5));
160                 } catch (ArithmeticException e) {
161                     failures++;
162                     System.err.println((new BigDecimal(powerOf2)).toString() + " / " +
163                                        (new BigDecimal(powerOf5)).toString() + " threw an exception.");
164                     e.printStackTrace();
165                 }
166
167                 try {
168                     bd = new BigDecimal(powerOf5).divide(new BigDecimal(powerOf2));
169                 } catch (ArithmeticException e) {
170                     failures++;
171                     System.err.println((new BigDecimal(powerOf5)).toString() + " / " +
172                                        (new BigDecimal(powerOf2)).toString() + " threw an exception.");
173
174                     e.printStackTrace();
175                 }
176
177             }
178         }
179         return failures;
180     }
181
182     public static int nonTerminating() {
183         int failures = 0;
184         int[] primes = {1, 3, 7, 13, 17};
185
186         // For each pair of prime products, verify the ratio of
187         // non-equal products has a non-terminating expansion.
188
189         for(int i = 0; i < primes.length; i++) {
190             for(int j = i+1; j < primes.length; j++) {
191
192                 for(int m = 0; m < primes.length; m++) {
193                     for(int n = m+1; n < primes.length; n++) {
194                         int dividend = primes[i] * primes[j];
195                         int divisor  = primes[m] * primes[n];
196
197                         if ( ((dividend/divisor) * divisor) != dividend ) {
198                             try {
199                                 BigDecimal quotient = (new BigDecimal(dividend).
200                                                        divide(new BigDecimal(divisor)));
201                                 failures++;
202                                 System.err.println("Exact quotient " + quotient.toString() +
203                                                    " returned for non-terminating fraction " +
204                                                    dividend + " / " + divisor + ".");
205                             }
206                             catch (ArithmeticException e) {
207                                 ; // Correct result
208                             }
209                         }
210
211                     }
212                 }
213             }
214         }
215
216         return failures;
217     }
218
219     public static int properScaleTests(){
220         int failures = 0;
221
222         BigDecimal[][] testCases = {
223             {new BigDecimal("1"),       new BigDecimal("5"),            new BigDecimal("2e-1")},
224             {new BigDecimal("1"),       new BigDecimal("50e-1"),        new BigDecimal("2e-1")},
225             {new BigDecimal("10e-1"),   new BigDecimal("5"),            new BigDecimal("2e-1")},
226             {new BigDecimal("1"),       new BigDecimal("500e-2"),       new BigDecimal("2e-1")},
227             {new BigDecimal("100e-2"),  new BigDecimal("5"),            new BigDecimal("20e-2")},
228             {new BigDecimal("1"),       new BigDecimal("32"),           new BigDecimal("3125e-5")},
229             {new BigDecimal("1"),       new BigDecimal("64"),           new BigDecimal("15625e-6")},
230             {new BigDecimal("1.0000000"),       new BigDecimal("64"),   new BigDecimal("156250e-7")},
231         };
232
233
234         for(BigDecimal[] tc : testCases) {
235             BigDecimal quotient;
236             if (! (quotient = tc[0].divide(tc[1])).equals(tc[2]) ) {
237                 failures++;
238                 System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
239                                    "; expected " + tc[2] + " got " + quotient);
240             }
241         }
242
243         return failures;
244     }
245
246     public static int trailingZeroTests() {
247         int failures = 0;
248
249         MathContext mc = new MathContext(3, RoundingMode.FLOOR);
250         BigDecimal[][] testCases = {
251             {new BigDecimal("19"),      new BigDecimal("100"),          new BigDecimal("0.19")},
252             {new BigDecimal("21"),      new BigDecimal("110"),          new BigDecimal("0.190")},
253         };
254
255         for(BigDecimal[] tc : testCases) {
256             BigDecimal quotient;
257             if (! (quotient = tc[0].divide(tc[1], mc)).equals(tc[2]) ) {
258                 failures++;
259                 System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
260                                    "; expected " + tc[2] + " got " + quotient);
261             }
262         }
263
264         return failures;
265     }
266
267     public static int scaledRoundedDivideTests() {
268         int failures = 0;
269         // Tests of the traditional scaled divide under different
270         // rounding modes.
271
272         // Encode rounding mode and scale for the divide in a
273         // BigDecimal with the significand equal to the rounding mode
274         // and the scale equal to the number's scale.
275
276         // {dividend, dividisor, rounding, quotient}
277         BigDecimal a = new BigDecimal("31415");
278         BigDecimal a_minus = a.negate();
279         BigDecimal b = new BigDecimal("10000");
280
281         BigDecimal c = new BigDecimal("31425");
282         BigDecimal c_minus = c.negate();
283
284         BigDecimal[][] testCases = {
285             {a,         b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("3.142")},
286             {a_minus,   b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("-3.142")},
287
288             {a,         b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("3.141")},
289             {a_minus,   b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("-3.141")},
290
291             {a,         b,      BigDecimal.valueOf(ROUND_CEILING, 3),   new BigDecimal("3.142")},
292             {a_minus,   b,      BigDecimal.valueOf(ROUND_CEILING, 3),   new BigDecimal("-3.141")},
293
294             {a,         b,      BigDecimal.valueOf(ROUND_FLOOR, 3),     new BigDecimal("3.141")},
295             {a_minus,   b,      BigDecimal.valueOf(ROUND_FLOOR, 3),     new BigDecimal("-3.142")},
296
297             {a,         b,      BigDecimal.valueOf(ROUND_HALF_UP, 3),   new BigDecimal("3.142")},
298             {a_minus,   b,      BigDecimal.valueOf(ROUND_HALF_UP, 3),   new BigDecimal("-3.142")},
299
300             {a,         b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("3.141")},
301             {a_minus,   b,      BigDecimal.valueOf(ROUND_DOWN, 3),      new BigDecimal("-3.141")},
302
303             {a,         b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
304             {a_minus,   b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
305
306             {c,         b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
307             {c_minus,   b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
308         };
309
310         for(BigDecimal tc[] : testCases) {
311             int scale = tc[2].scale();
312             int rm = tc[2].unscaledValue().intValue();
313
314             BigDecimal quotient = tc[0].divide(tc[1], scale, rm);
315             if (!quotient.equals(tc[3])) {
316                 failures++;
317                 System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
318                                    " scale " + scale + " rounding mode " + RoundingMode.valueOf(rm) +
319                                    "; expected " + tc[3] + " got " + quotient);
320             }
321         }
322
323         return failures;
324     }
325
326     public static void main(String argv[]) {
327         int failures = 0;
328
329         failures += powersOf2and5();
330         failures += nonTerminating();
331         failures += properScaleTests();
332         failures += trailingZeroTests();
333         failures += scaledRoundedDivideTests();
334
335         if (failures > 0) {
336             throw new RuntimeException("Incurred " + failures +
337                                        " failures while testing exact divide.");
338         }
339     }
340 }
```