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