1 /*
2  * Copyright (c) 2006, 2018, 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 
24 /*
25  * @test
26  * @bug 6362557 8200698
27  * @summary Some tests of add(BigDecimal, mc)
28  * @author Joseph D. Darcy
29  */
30 
31 import java.math.*;
32 import static java.math.BigDecimal.*;
33 import java.util.Set;
34 import java.util.EnumSet;
35 
36 public class AddTests {
37 
38     private static Set<RoundingMode> nonExactRoundingModes =
39         EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY));
40 
41     /**
42      * Test for some simple additions, particularly, it will test
43      * the overflow case.
44      */
simpleTests()45     private static int simpleTests() {
46         int failures = 0;
47 
48         BigDecimal[] bd1 = {
49             new BigDecimal(new BigInteger("7812404666936930160"), 11),
50             new BigDecimal(new BigInteger("7812404666936930160"), 12),
51             new BigDecimal(new BigInteger("7812404666936930160"), 13),
52         };
53         BigDecimal bd2 = new BigDecimal(new BigInteger("2790000"), 1);
54         BigDecimal[] expectedResult = {
55             new BigDecimal("78403046.66936930160"),
56             new BigDecimal("8091404.666936930160"),
57             new BigDecimal("1060240.4666936930160"),
58         };
59         for (int i = 0; i < bd1.length; i++) {
60             if (!bd1[i].add(bd2).equals(expectedResult[i]))
61                 failures++;
62         }
63         return failures;
64     }
65 
66     /**
67      * Test for extreme value of scale and rounding precision that
68      * could cause integer overflow in right-shift-into-sticky-bit
69      * computations.
70      */
extremaTests()71     private static int extremaTests() {
72         int failures = 0;
73 
74         failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE),
75                                         valueOf(2, Integer.MAX_VALUE), null);
76         failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE),
77                                         valueOf(-2, Integer.MAX_VALUE), null);
78         return failures;
79     }
80 
81     /**
82      * Print sum of b1 and b2; correct result will not throw an
83      * exception.
84      */
addWithoutException(BigDecimal b1, BigDecimal b2, MathContext mc)85     private static int addWithoutException(BigDecimal b1, BigDecimal b2, MathContext mc) {
86         if (mc == null)
87             mc = new MathContext(2, RoundingMode.DOWN);
88 
89         try {
90             BigDecimal sum = b1.add(b2, mc);
91             printAddition(b1, b2, sum.toString());
92             return 0;
93         } catch(ArithmeticException ae) {
94             printAddition(b1, b2, "Exception!");
95             return 1;
96         }
97     }
98 
99     /**
100      * Test combinations of operands that may meet the condensation
101      * criteria when rounded to different precisions.
102      */
roundingGradationTests()103     private static int roundingGradationTests() {
104         int failures = 0;
105 
106         failures += roundAway(new BigDecimal("1234e100"),
107                               new BigDecimal(   "1234e97"));
108 
109         failures += roundAway(new BigDecimal("1234e100"),
110                               new BigDecimal(    "1234e96"));
111 
112         failures += roundAway(new BigDecimal("1234e100"),
113                               new BigDecimal(     "1234e95"));
114 
115         failures += roundAway(new BigDecimal("1234e100"),
116                               new BigDecimal(      "1234e94"));
117 
118         failures += roundAway(new BigDecimal("1234e100"),
119                               new BigDecimal(       "1234e93"));
120 
121         failures += roundAway(new BigDecimal("1234e100"),
122                               new BigDecimal(        "1234e92"));
123 
124         failures += roundAway(new BigDecimal("1234e100"),
125                               new BigDecimal("1234e50"));
126 
127 
128         failures += roundAway(new BigDecimal("1000e100"),
129                               new BigDecimal(   "1234e97"));
130 
131         failures += roundAway(new BigDecimal("1000e100"),
132                               new BigDecimal(    "1234e96"));
133 
134         failures += roundAway(new BigDecimal("1000e100"),
135                               new BigDecimal(     "1234e95"));
136 
137         failures += roundAway(new BigDecimal("1000e100"),
138                               new BigDecimal(      "1234e94"));
139 
140         failures += roundAway(new BigDecimal("1000e100"),
141                               new BigDecimal(       "1234e93"));
142 
143         failures += roundAway(new BigDecimal("1000e100"),
144                               new BigDecimal(        "1234e92"));
145 
146         failures += roundAway(new BigDecimal("1000e100"),
147                               new BigDecimal("1234e50"));
148 
149 
150 
151         failures += roundAway(new BigDecimal("1999e100"),
152                               new BigDecimal(   "1234e97"));
153 
154         failures += roundAway(new BigDecimal("1999e100"),
155                               new BigDecimal(    "1234e96"));
156 
157         failures += roundAway(new BigDecimal("1999e100"),
158                               new BigDecimal(     "1234e95"));
159 
160         failures += roundAway(new BigDecimal("1999e100"),
161                               new BigDecimal(      "1234e94"));
162 
163         failures += roundAway(new BigDecimal("1999e100"),
164                               new BigDecimal(       "1234e93"));
165 
166         failures += roundAway(new BigDecimal("1999e100"),
167                               new BigDecimal(        "1234e92"));
168 
169         failures += roundAway(new BigDecimal("1999e100"),
170                               new BigDecimal("1234e50"));
171 
172 
173 
174         failures += roundAway(new BigDecimal("9999e100"),
175                               new BigDecimal(   "1234e97"));
176 
177         failures += roundAway(new BigDecimal("9999e100"),
178                               new BigDecimal(    "1234e96"));
179 
180         failures += roundAway(new BigDecimal("9999e100"),
181                               new BigDecimal(     "1234e95"));
182 
183         failures += roundAway(new BigDecimal("9999e100"),
184                               new BigDecimal(      "1234e94"));
185 
186         failures += roundAway(new BigDecimal("9999e100"),
187                               new BigDecimal(       "1234e93"));
188 
189         failures += roundAway(new BigDecimal("9999e100"),
190                               new BigDecimal(        "1234e92"));
191 
192         failures += roundAway(new BigDecimal("9999e100"),
193                               new BigDecimal("1234e50"));
194 
195         return failures;
196     }
197 
printAddition(BigDecimal b1, BigDecimal b2, String s)198     private static void printAddition(BigDecimal b1, BigDecimal b2, String s) {
199         System.out.println("" + b1+ "\t+\t" + b2 + "\t=\t" + s);
200     }
201 
roundAway(BigDecimal b1, BigDecimal b2)202     private static int roundAway(BigDecimal b1, BigDecimal b2) {
203         int failures = 0;
204 
205         b1.precision();
206         b2.precision();
207 
208         BigDecimal b1_negate = b1.negate();
209         BigDecimal b2_negate = b2.negate();
210 
211         b1_negate.precision();
212         b2_negate.precision();
213 
214         failures += roundAway1(b1,        b2);
215         failures += roundAway1(b1,        b2_negate);
216         failures += roundAway1(b1_negate, b2);
217         failures += roundAway1(b1_negate, b2_negate);
218 
219         return failures;
220     }
221 
roundAway1(BigDecimal b1, BigDecimal b2)222     private static int roundAway1(BigDecimal b1, BigDecimal b2) {
223         int failures = 0;
224         failures += roundAway0(b1, b2);
225         failures += roundAway0(b2, b1);
226         return failures;
227     }
228 
229     /**
230      * Compare b1.add(b2, mc) with b1.add(b2).round(mc) for a variety
231      * of MathContexts.
232      */
roundAway0(BigDecimal b1, BigDecimal b2)233     private static int roundAway0(BigDecimal b1, BigDecimal b2) {
234         int failures = 0;
235         BigDecimal exactSum = b1.add(b2);
236 
237         for(int precision = 1 ; precision < exactSum.precision()+2; precision++) {
238             for(RoundingMode rm : nonExactRoundingModes) {
239                 MathContext mc = new MathContext(precision, rm);
240                 BigDecimal roundedExactSum = exactSum.round(mc);
241 
242                 try {
243                     BigDecimal sum = b1.add(b2, mc);
244 
245                     if (!roundedExactSum.equals(sum) ) {
246                         failures++;
247                         System.out.println("Exact sum " + exactSum +
248                                            "\trounded by " + mc +
249                                            "\texpected: " + roundedExactSum + " got: ");
250                         printAddition(b1, b2, sum.toString());
251                     }
252 //                  else {
253 //                      System.out.print(mc + "\t");
254 //                      printAddition(b1, b2, sum.toString());
255 //                  }
256 
257                 } catch (ArithmeticException ae) {
258                     printAddition(b1, b2, "Exception!");
259                     failures++;
260                 }
261             }
262         }
263 
264         return failures;
265     }
266 
267     /**
268      * Verify calling the precision method should not change the
269      * computed result.
270      */
precisionConsistencyTest()271     private static int precisionConsistencyTest() {
272         int failures = 0;
273         MathContext mc = new MathContext(1,RoundingMode.DOWN);
274         BigDecimal a = BigDecimal.valueOf(1999, -1); //value is equivalent to 19990
275 
276         BigDecimal sum1 = a.add(BigDecimal.ONE, mc);
277         a.precision();
278         BigDecimal sum2 = a.add(BigDecimal.ONE, mc);
279 
280         if (!sum1.equals(sum2)) {
281             failures ++;
282             System.out.println("Unequal sums after calling precision!");
283             System.out.print("Before:\t");
284             printAddition(a, BigDecimal.ONE, sum1.toString());
285 
286             System.out.print("After:\t");
287             printAddition(a, BigDecimal.ONE, sum2.toString());
288         }
289 
290         return failures;
291     }
292 
arithmeticExceptionTest()293     private static int arithmeticExceptionTest() {
294         int failures = 0;
295         BigDecimal x;
296         try {
297             //
298             // The string representation "1e2147483647", which is equivalent
299             // to 10^Integer.MAX_VALUE, is used to create an augend with an
300             // unscaled value of 1 and a scale of -Integer.MAX_VALUE. The
301             // addend "1" has an unscaled value of 1 with a scale of 0. The
302             // addition is performed exactly and is specified to have a
303             // preferred scale of max(-Integer.MAX_VALUE, 0). As the scale
304             // of the result is 0, a value with Integer.MAX_VALUE + 1 digits
305             // would need to be created. Therefore the next statement is
306             // expected to overflow with an ArithmeticException.
307             //
308             x = new BigDecimal("1e2147483647").add(new BigDecimal(1));
309             failures++;
310         } catch (ArithmeticException ae) {
311         }
312         return failures;
313     }
314 
main(String argv[])315     public static void main(String argv[]) {
316         int failures = 0;
317 
318         failures += extremaTests();
319         failures += roundingGradationTests();
320         failures += precisionConsistencyTest();
321         failures += arithmeticExceptionTest();
322 
323         if (failures > 0) {
324             throw new RuntimeException("Incurred " + failures +
325                                        " failures while testing rounding add.");
326         }
327     }
328 }
329