1 /*
2  * Copyright (c) 2019, 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 8211936
27  * @summary Tests of BigDecimal.intValue() and BigDecimal.longValue()
28  */
29 package test.java.math.BigDecimal;
30 
31 import java.math.BigDecimal;
32 import java.util.Map;
33 
34 public class IntegralValueTests {
main(String... args)35     public static void main(String... args) {
36         int failures =
37             integralValuesTest(INT_VALUES, true) +
38             integralValuesTest(LONG_VALUES, false);
39         if (failures != 0) {
40             throw new RuntimeException
41                 ("Incurred " + failures + " failures for {int,long}Value().");
42         }
43     }
44 
45     private static final Map<BigDecimal, Number> INT_VALUES =
46         Map.ofEntries(
47 
48          // 2**31 - 1
49          Map.entry(new BigDecimal("2147483647"), Integer.MAX_VALUE),
50          Map.entry(new BigDecimal("2147483647.0"), Integer.MAX_VALUE),
51          Map.entry(new BigDecimal("2147483647.00"), Integer.MAX_VALUE),
52 
53          Map.entry(new BigDecimal("-2147483647"), -Integer.MAX_VALUE),
54          Map.entry(new BigDecimal("-2147483647.0"), -Integer.MAX_VALUE),
55 
56          // -2**31
57          Map.entry(new BigDecimal("-2147483648"), Integer.MIN_VALUE),
58          Map.entry(new BigDecimal("-2147483648.1"), Integer.MIN_VALUE),
59          Map.entry(new BigDecimal("-2147483648.01"), Integer.MIN_VALUE),
60 
61          // -2**31 + 1 truncation to 2**31 - 1
62          Map.entry(new BigDecimal("-2147483649"), Integer.MAX_VALUE),
63 
64          // 2**64 - 1 truncation to 1
65          Map.entry(new BigDecimal("4294967295"), -1),
66 
67          // 2**64 truncation to 0
68          Map.entry(new BigDecimal("4294967296"), 0),
69 
70          // Fast path truncation to 0
71          Map.entry(new BigDecimal("1e32"), 0),
72 
73          // Slow path truncation to -2**31
74          Map.entry(new BigDecimal("1e31"), Integer.MIN_VALUE),
75 
76          // Slow path
77          Map.entry(new BigDecimal("1e0"), 1),
78 
79          // Fast path round to 0
80          Map.entry(new BigDecimal("9e-1"), 0),
81 
82          // Some random values
83          Map.entry(new BigDecimal("900e-1"), 90), // Increasing negative exponents
84          Map.entry(new BigDecimal("900e-2"), 9),
85          Map.entry(new BigDecimal("900e-3"), 0),
86 
87          // Fast path round to 0
88          Map.entry(new BigDecimal("123456789e-9"), 0),
89 
90          // Slow path round to 1
91          Map.entry(new BigDecimal("123456789e-8"), 1),
92 
93          // Increasing positive exponents
94          Map.entry(new BigDecimal("10000001e1"), 100000010),
95          Map.entry(new BigDecimal("10000001e10"), -1315576832),
96          Map.entry(new BigDecimal("10000001e100"), 0),
97          Map.entry(new BigDecimal("10000001e1000"), 0),
98          Map.entry(new BigDecimal("10000001e10000"), 0),
99          Map.entry(new BigDecimal("10000001e100000"), 0),
100          Map.entry(new BigDecimal("10000001e1000000"), 0),
101          Map.entry(new BigDecimal("10000001e10000000"), 0),
102          Map.entry(new BigDecimal("10000001e100000000"), 0),
103          Map.entry(new BigDecimal("10000001e1000000000"), 0),
104 
105          // Increasing negative exponents
106          Map.entry(new BigDecimal("10000001e-1"), 1000000),
107          Map.entry(new BigDecimal("10000001e-10"), 0),
108          Map.entry(new BigDecimal("10000001e-100"), 0),
109          Map.entry(new BigDecimal("10000001e-1000"), 0),
110          Map.entry(new BigDecimal("10000001e-10000"), 0),
111          Map.entry(new BigDecimal("10000001e-100000"), 0),
112          Map.entry(new BigDecimal("10000001e-1000000"), 0),
113          Map.entry(new BigDecimal("10000001e-10000000"), 0),
114          Map.entry(new BigDecimal("10000001e-100000000"), 0),
115          Map.entry(new BigDecimal("10000001e-1000000000"), 0),
116 
117          // Currency calculation to 4 places
118          Map.entry(new BigDecimal("12345.0001"), 12345),
119          Map.entry(new BigDecimal("12345.9999"), 12345),
120          Map.entry(new BigDecimal("-12345.0001"), -12345),
121          Map.entry(new BigDecimal("-12345.9999"), -12345));
122 
123     private static final Map<BigDecimal, Number> LONG_VALUES =
124         Map.ofEntries(
125          // 2**63 - 1
126          Map.entry(new BigDecimal("9223372036854775807"), Long.MAX_VALUE),
127          Map.entry(new BigDecimal("9223372036854775807.0"), Long.MAX_VALUE),
128          Map.entry(new BigDecimal("9223372036854775807.00"), Long.MAX_VALUE),
129 
130          // 2**63 truncation to -2**63
131          Map.entry(new BigDecimal("-9223372036854775808"), Long.MIN_VALUE),
132          Map.entry(new BigDecimal("-9223372036854775808.1"), Long.MIN_VALUE),
133          Map.entry(new BigDecimal("-9223372036854775808.01"), Long.MIN_VALUE),
134 
135          // -2**63 + 1 truncation to 2**63 - 1
136          Map.entry(new BigDecimal("-9223372036854775809"), 9223372036854775807L),
137 
138          // 2**64 - 1 truncation to -1
139          Map.entry(new BigDecimal("18446744073709551615"), -1L),
140 
141          // 2**64 truncation to 0
142          Map.entry(new BigDecimal("18446744073709551616"), 0L),
143 
144          // Slow path truncation to -2**63
145          Map.entry(new BigDecimal("1e63"),  -9223372036854775808L),
146          Map.entry(new BigDecimal("-1e63"), -9223372036854775808L),
147          // Fast path with larger magnitude scale
148          Map.entry(new BigDecimal("1e64"), 0L),
149          Map.entry(new BigDecimal("-1e64"), 0L),
150          Map.entry(new BigDecimal("1e65"), 0L),
151          Map.entry(new BigDecimal("-1e65"), 0L),
152 
153          // Slow path
154          Map.entry(new BigDecimal("1e0"), 1L),
155 
156          // Fast path round to 0
157          Map.entry(new BigDecimal("9e-1"), 0L),
158 
159          // Some random values
160          Map.entry(new BigDecimal("900e-1"), 90L), // Increasing negative exponents
161          Map.entry(new BigDecimal("900e-2"), 9L),
162          Map.entry(new BigDecimal("900e-3"), 0L),
163 
164          // Fast path round to 0
165          Map.entry(new BigDecimal("123456789e-9"), 0L),
166 
167          // Slow path round to 1
168          Map.entry(new BigDecimal("123456789e-8"), 1L),
169 
170          // Increasing positive exponents
171          Map.entry(new BigDecimal("10000001e1"), 100000010L),
172          Map.entry(new BigDecimal("10000001e10"), 100000010000000000L),
173          Map.entry(new BigDecimal("10000001e100"), 0L),
174          Map.entry(new BigDecimal("10000001e1000"), 0L),
175          Map.entry(new BigDecimal("10000001e10000"), 0L),
176          Map.entry(new BigDecimal("10000001e100000"), 0L),
177          Map.entry(new BigDecimal("10000001e1000000"), 0L),
178          Map.entry(new BigDecimal("10000001e10000000"), 0L),
179          Map.entry(new BigDecimal("10000001e100000000"), 0L),
180          Map.entry(new BigDecimal("10000001e1000000000"), 0L),
181 
182          // Increasing negative exponents
183          Map.entry(new BigDecimal("10000001e-1"), 1000000L),
184          Map.entry(new BigDecimal("10000001e-10"), 0L),
185          Map.entry(new BigDecimal("10000001e-100"), 0L),
186          Map.entry(new BigDecimal("10000001e-1000"), 0L),
187          Map.entry(new BigDecimal("10000001e-10000"), 0L),
188          Map.entry(new BigDecimal("10000001e-100000"), 0L),
189          Map.entry(new BigDecimal("10000001e-1000000"), 0L),
190          Map.entry(new BigDecimal("10000001e-10000000"), 0L),
191          Map.entry(new BigDecimal("10000001e-100000000"), 0L),
192          Map.entry(new BigDecimal("10000001e-1000000000"), 0L),
193 
194          // Currency calculation to 4 places
195          Map.entry(new BigDecimal("12345.0001"), 12345L),
196          Map.entry(new BigDecimal("12345.9999"), 12345L),
197          Map.entry(new BigDecimal("-12345.0001"), -12345L),
198          Map.entry(new BigDecimal("-12345.9999"), -12345L));
199 
integralValuesTest(Map<BigDecimal, Number> v, boolean isInt)200     private static int integralValuesTest(Map<BigDecimal, Number> v, boolean isInt) {
201         System.err.format("Testing %s%n", isInt ? "Integer" : "Long");
202         int failures = 0;
203         for (var testCase : v.entrySet()) {
204             BigDecimal bd = testCase.getKey();
205             Number expected = testCase.getValue();
206             try {
207                 if (isInt) {
208                     int intValue = bd.intValue();
209                     if (intValue != (int)expected) {
210                         failures += reportError(bd, expected, intValue, isInt);
211                     }
212                 } else {
213                     long longValue = bd.longValue();
214                     if (longValue != (long)expected) {
215                         failures += reportError(bd, expected, longValue, isInt);
216                     }
217                 }
218             } catch (Exception e) {
219                 failures++;
220                 System.err.format("Unexpected exception %s for %s%n",
221                                   e, bd.toString());
222             }
223         }
224         return failures;
225     }
226 
reportError(BigDecimal bd, Number expected, long longValue, boolean isInt)227     private static int reportError(BigDecimal bd, Number expected, long longValue, boolean isInt) {
228         // Android-changed: Avoid conditional expression since JLS 15.25.2 promotes Integer to Long.
229         // This patch can be upstreamed in the future.
230         // System.err.format("For %s, scale=%d, expected %d, actual %d, simple %d%n",
231         //         bd.toString(), bd.scale(),
232         //         (isInt ? (Integer) expected : (Long) expected ),
233         //         longValue,
234         //         (isInt ? simpleIntValue(bd): simpleLongValue(bd) ));
235         if (isInt) {
236             System.err.format("For %s, scale=%d, expected %d, actual %d, simple %d%n",
237                     bd.toString(), bd.scale(), expected, longValue, simpleIntValue(bd));
238         } else {
239             System.err.format("For %s, scale=%d, expected %d, actual %d, simple %d%n",
240                     bd.toString(), bd.scale(), expected, longValue, simpleLongValue(bd));
241         }
242         return 1;
243     }
244 
simpleLongValue(BigDecimal bd)245     private static long simpleLongValue(BigDecimal bd) {
246         return bd.toBigInteger().longValue();
247     }
248 
simpleIntValue(BigDecimal bd)249     private static int simpleIntValue(BigDecimal bd) {
250         return bd.toBigInteger().intValue();
251     }
252 }
253