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