1 /* 2 * Copyright 2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 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 6362557 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 extreme value of scale and rounding precision that 43 * could cause integer overflow in right-shift-into-sticky-bit 44 * computations. 45 */ 46 private static int extremaTests() { 47 int failures = 0; 48 49 failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE), 50 valueOf(2, Integer.MAX_VALUE), null); 51 failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE), 52 valueOf(-2, Integer.MAX_VALUE), null); 53 return failures; 54 } 55 56 /** 57 * Print sum of b1 and b2; correct result will not throw an 58 * exception. 59 */ 60 private static int addWithoutException(BigDecimal b1, BigDecimal b2, MathContext mc) { 61 if (mc == null) 62 mc = new MathContext(2, RoundingMode.DOWN); 63 64 try { 65 BigDecimal sum = b1.add(b2, mc); 66 printAddition(b1, b2, sum.toString()); 67 return 0; 68 } catch(ArithmeticException ae) { 69 printAddition(b1, b2, "Exception!"); 70 return 1; 71 } 72 } 73 74 /** 75 * Test combinations of operands that may meet the condensation 76 * criteria when rounded to different precisions. 77 */ 78 private static int roundingGradationTests() { 79 int failures = 0; 80 81 failures += roundAway(new BigDecimal("1234e100"), 82 new BigDecimal( "1234e97")); 83 84 failures += roundAway(new BigDecimal("1234e100"), 85 new BigDecimal( "1234e96")); 86 87 failures += roundAway(new BigDecimal("1234e100"), 88 new BigDecimal( "1234e95")); 89 90 failures += roundAway(new BigDecimal("1234e100"), 91 new BigDecimal( "1234e94")); 92 93 failures += roundAway(new BigDecimal("1234e100"), 94 new BigDecimal( "1234e93")); 95 96 failures += roundAway(new BigDecimal("1234e100"), 97 new BigDecimal( "1234e92")); 98 99 failures += roundAway(new BigDecimal("1234e100"), 100 new BigDecimal("1234e50")); 101 102 103 failures += roundAway(new BigDecimal("1000e100"), 104 new BigDecimal( "1234e97")); 105 106 failures += roundAway(new BigDecimal("1000e100"), 107 new BigDecimal( "1234e96")); 108 109 failures += roundAway(new BigDecimal("1000e100"), 110 new BigDecimal( "1234e95")); 111 112 failures += roundAway(new BigDecimal("1000e100"), 113 new BigDecimal( "1234e94")); 114 115 failures += roundAway(new BigDecimal("1000e100"), 116 new BigDecimal( "1234e93")); 117 118 failures += roundAway(new BigDecimal("1000e100"), 119 new BigDecimal( "1234e92")); 120 121 failures += roundAway(new BigDecimal("1000e100"), 122 new BigDecimal("1234e50")); 123 124 125 126 failures += roundAway(new BigDecimal("1999e100"), 127 new BigDecimal( "1234e97")); 128 129 failures += roundAway(new BigDecimal("1999e100"), 130 new BigDecimal( "1234e96")); 131 132 failures += roundAway(new BigDecimal("1999e100"), 133 new BigDecimal( "1234e95")); 134 135 failures += roundAway(new BigDecimal("1999e100"), 136 new BigDecimal( "1234e94")); 137 138 failures += roundAway(new BigDecimal("1999e100"), 139 new BigDecimal( "1234e93")); 140 141 failures += roundAway(new BigDecimal("1999e100"), 142 new BigDecimal( "1234e92")); 143 144 failures += roundAway(new BigDecimal("1999e100"), 145 new BigDecimal("1234e50")); 146 147 148 149 failures += roundAway(new BigDecimal("9999e100"), 150 new BigDecimal( "1234e97")); 151 152 failures += roundAway(new BigDecimal("9999e100"), 153 new BigDecimal( "1234e96")); 154 155 failures += roundAway(new BigDecimal("9999e100"), 156 new BigDecimal( "1234e95")); 157 158 failures += roundAway(new BigDecimal("9999e100"), 159 new BigDecimal( "1234e94")); 160 161 failures += roundAway(new BigDecimal("9999e100"), 162 new BigDecimal( "1234e93")); 163 164 failures += roundAway(new BigDecimal("9999e100"), 165 new BigDecimal( "1234e92")); 166 167 failures += roundAway(new BigDecimal("9999e100"), 168 new BigDecimal("1234e50")); 169 170 return failures; 171 } 172 173 private static void printAddition(BigDecimal b1, BigDecimal b2, String s) { 174 System.out.println("" + b1+ "\t+\t" + b2 + "\t=\t" + s); 175 } 176 177 private static int roundAway(BigDecimal b1, BigDecimal b2) { 178 int failures = 0; 179 180 b1.precision(); 181 b2.precision(); 182 183 BigDecimal b1_negate = b1.negate(); 184 BigDecimal b2_negate = b2.negate(); 185 186 b1_negate.precision(); 187 b2_negate.precision(); 188 189 failures += roundAway1(b1, b2); 190 failures += roundAway1(b1, b2_negate); 191 failures += roundAway1(b1_negate, b2); 192 failures += roundAway1(b1_negate, b2_negate); 193 194 return failures; 195 } 196 197 private static int roundAway1(BigDecimal b1, BigDecimal b2) { 198 int failures = 0; 199 failures += roundAway0(b1, b2); 200 failures += roundAway0(b2, b1); 201 return failures; 202 } 203 204 /** 205 * Compare b1.add(b2, mc) with b1.add(b2).round(mc) for a variety 206 * of MathContexts. 207 */ 208 private static int roundAway0(BigDecimal b1, BigDecimal b2) { 209 int failures = 0; 210 BigDecimal exactSum = b1.add(b2); 211 212 for(int precision = 1 ; precision < exactSum.precision()+2; precision++) { 213 for(RoundingMode rm : nonExactRoundingModes) { 214 MathContext mc = new MathContext(precision, rm); 215 BigDecimal roundedExactSum = exactSum.round(mc); 216 217 try { 218 BigDecimal sum = b1.add(b2, mc); 219 220 if (!roundedExactSum.equals(sum) ) { 221 failures++; 222 System.out.println("Exact sum " + exactSum + 223 "\trounded by " + mc + 224 "\texpected: " + roundedExactSum + " got: "); 225 printAddition(b1, b2, sum.toString()); 226 } 227 // else { 228 // System.out.print(mc + "\t"); 229 // printAddition(b1, b2, sum.toString()); 230 // } 231 232 } catch (ArithmeticException ae) { 233 printAddition(b1, b2, "Exception!"); 234 failures++; 235 } 236 } 237 } 238 239 return failures; 240 } 241 242 /** 243 * Verify calling the precision method should not change the 244 * computed result. 245 */ 246 private static int precisionConsistencyTest() { 247 int failures = 0; 248 MathContext mc = new MathContext(1,RoundingMode.DOWN); 249 BigDecimal a = BigDecimal.valueOf(1999, -1); //value is equivalent to 19990 250 251 BigDecimal sum1 = a.add(BigDecimal.ONE, mc); 252 a.precision(); 253 BigDecimal sum2 = a.add(BigDecimal.ONE, mc); 254 255 if (!sum1.equals(sum2)) { 256 failures ++; 257 System.out.println("Unequal sums after calling precision!"); 258 System.out.print("Before:\t"); 259 printAddition(a, BigDecimal.ONE, sum1.toString()); 260 261 System.out.print("After:\t"); 262 printAddition(a, BigDecimal.ONE, sum2.toString()); 263 } 264 265 return failures; 266 } 267 268 public static void main(String argv[]) { 269 int failures = 0; 270 271 failures += extremaTests(); 272 failures += roundingGradationTests(); 273 failures += precisionConsistencyTest(); 274 275 if (failures > 0) { 276 throw new RuntimeException("Incurred " + failures + 277 " failures while testing rounding add."); 278 } 279 } 280 }