1 /* 2 * Copyright 2003 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 4902952 4905407 4916149 27 * @summary Tests that the scale of zero is propagated properly and has the proper effect. 28 * @author Joseph D. Darcy 29 * @compile -source 1.5 ZeroScalingTests.java 30 * @run main ZeroScalingTests 31 */ 32 33 import java.math.*; 34 import java.util.*; 35 36 public class ZeroScalingTests { 37 38 static MathContext longEnough = new MathContext(50, RoundingMode.UNNECESSARY); 39 40 static BigDecimal[] zeros = new BigDecimal[23]; 41 static { 42 for(int i = 0; i < 21; i++) { 43 zeros[i] = new BigDecimal(BigInteger.ZERO, i-10); 44 } 45 zeros[21] = new BigDecimal(BigInteger.ZERO, Integer.MIN_VALUE); 46 zeros[22] = new BigDecimal(BigInteger.ZERO, Integer.MAX_VALUE); 47 } 48 49 static BigDecimal element = BigDecimal.valueOf(100, -2); 50 51 static MathContext contexts[] = { 52 new MathContext(0, RoundingMode.UNNECESSARY), 53 new MathContext(100, RoundingMode.UNNECESSARY), 54 new MathContext(5, RoundingMode.UNNECESSARY), 55 new MathContext(4, RoundingMode.UNNECESSARY), 56 new MathContext(3, RoundingMode.UNNECESSARY), 57 new MathContext(2, RoundingMode.UNNECESSARY), 58 new MathContext(1, RoundingMode.UNNECESSARY), 59 }; 60 61 62 static int addTests() { 63 int failures = 0; 64 65 for(BigDecimal zero1: zeros) { 66 for(BigDecimal zero2: zeros) { 67 BigDecimal expected = new BigDecimal(BigInteger.ZERO, 68 Math.max(zero1.scale(), zero2.scale())); 69 BigDecimal result; 70 71 if(! (result=zero1.add(zero2)).equals(expected) ) { 72 failures++; 73 System.err.println("For classic exact add, expected scale of " + 74 expected.scale() + "; got " + 75 result.scale() + "."); 76 } 77 78 if(! (result=zero1.add(zero2, MathContext.UNLIMITED)).equals(expected) ) { 79 failures++; 80 System.err.println("For UNLIMITED math context add," + 81 " expected scale of " + 82 expected.scale() + "; got " + 83 result.scale() + "."); 84 } 85 86 if(! (result=zero1.add(zero2, longEnough)).equals(expected) ) { 87 failures++; 88 System.err.println("For longEnough math context add," + 89 " expected scale of " + 90 expected.scale() + "; got " + 91 result.scale() + "."); 92 } 93 94 } 95 } 96 97 // Test effect of adding zero to a nonzero value. 98 for (MathContext mc: contexts) { 99 for (BigDecimal zero: zeros) { 100 if (Math.abs((long)zero.scale()) < 100 ) { 101 102 int preferredScale = Math.max(zero.scale(), element.scale()); 103 if (mc.getPrecision() != 0) { 104 if (preferredScale < -4 ) 105 preferredScale = -4; 106 else if (preferredScale > -(5 - mc.getPrecision())) { 107 preferredScale = -(5 - mc.getPrecision()); 108 } 109 } 110 111 112 /* 113 System.err.println("\n " + element + " +\t" + zero + " =\t" + result); 114 115 System.err.println("scales" + element.scale() + " \t" + zero.scale() + 116 " \t " + result.scale() + "\t precison = " + mc.getPrecision()); 117 System.err.println("expected scale = " + preferredScale); 118 */ 119 120 BigDecimal result = element.add(zero, mc); 121 if (result.scale() != preferredScale || 122 result.compareTo(element) != 0) { 123 failures++; 124 System.err.println("Expected scale " + preferredScale + 125 " result scale was " + result.scale() + 126 " ; value was " + result); 127 } 128 129 result = zero.add(element, mc); 130 if (result.scale() != preferredScale || 131 result.compareTo(element) != 0) { 132 failures++; 133 System.err.println("Expected scale " + preferredScale + 134 " result scale was " + result.scale() + 135 " ; value was " + result); 136 } 137 138 result = element.negate().add(zero, mc); 139 if (result.scale() != preferredScale || 140 result.compareTo(element.negate()) != 0) { 141 failures++; 142 System.err.println("Expected scale " + preferredScale + 143 " result scale was " + result.scale() + 144 " ; value was " + result); 145 } 146 147 result = zero.add(element.negate(), mc); 148 if (result.scale() != preferredScale || 149 result.compareTo(element.negate()) != 0) { 150 failures++; 151 System.err.println("Expected scale " + preferredScale + 152 " result scale was " + result.scale() + 153 " ; value was " + result); 154 } 155 156 } 157 } 158 } 159 160 return failures; 161 } 162 163 static int subtractTests() { 164 int failures = 0; 165 166 for(BigDecimal zero1: zeros) { 167 for(BigDecimal zero2: zeros) { 168 BigDecimal expected = new BigDecimal(BigInteger.ZERO, 169 Math.max(zero1.scale(), zero2.scale())); 170 BigDecimal result; 171 172 if(! (result=zero1.subtract(zero2)).equals(expected) ) { 173 failures++; 174 System.err.println("For classic exact subtract, expected scale of " + 175 expected.scale() + "; got " + 176 result.scale() + "."); 177 } 178 179 if(! (result=zero1.subtract(zero2, MathContext.UNLIMITED)).equals(expected) ) { 180 failures++; 181 System.err.println("For UNLIMITED math context subtract," + 182 " expected scale of " + 183 expected.scale() + "; got " + 184 result.scale() + "."); 185 } 186 187 if(! (result=zero1.subtract(zero2, longEnough)).equals(expected) ) { 188 failures++; 189 System.err.println("For longEnough math context subtract," + 190 " expected scale of " + 191 expected.scale() + "; got " + 192 result.scale() + "."); 193 } 194 195 } 196 } 197 198 199 // Test effect of adding zero to a nonzero value. 200 for (MathContext mc: contexts) { 201 for (BigDecimal zero: zeros) { 202 if (Math.abs((long)zero.scale()) < 100 ) { 203 204 int preferredScale = Math.max(zero.scale(), element.scale()); 205 if (mc.getPrecision() != 0) { 206 if (preferredScale < -4 ) 207 preferredScale = -4; 208 else if (preferredScale > -(5 - mc.getPrecision())) { 209 preferredScale = -(5 - mc.getPrecision()); 210 } 211 } 212 213 214 /* 215 System.err.println("\n " + element + " +\t" + zero + " =\t" + result); 216 217 System.err.println("scales" + element.scale() + " \t" + zero.scale() + 218 " \t " + result.scale() + "\t precison = " + mc.getPrecision()); 219 System.err.println("expected scale = " + preferredScale); 220 */ 221 222 BigDecimal result = element.subtract(zero, mc); 223 if (result.scale() != preferredScale || 224 result.compareTo(element) != 0) { 225 failures++; 226 System.err.println("Expected scale " + preferredScale + 227 " result scale was " + result.scale() + 228 " ; value was " + result); 229 } 230 231 result = zero.subtract(element, mc); 232 if (result.scale() != preferredScale || 233 result.compareTo(element.negate()) != 0) { 234 failures++; 235 System.err.println("Expected scale " + preferredScale + 236 " result scale was " + result.scale() + 237 " ; value was " + result); 238 } 239 240 result = element.negate().subtract(zero, mc); 241 if (result.scale() != preferredScale || 242 result.compareTo(element.negate()) != 0) { 243 failures++; 244 System.err.println("Expected scale " + preferredScale + 245 " result scale was " + result.scale() + 246 " ; value was " + result); 247 } 248 249 result = zero.subtract(element.negate(), mc); 250 if (result.scale() != preferredScale || 251 result.compareTo(element) != 0) { 252 failures++; 253 System.err.println("Expected scale " + preferredScale + 254 " result scale was " + result.scale() + 255 " ; value was " + result); 256 } 257 258 } 259 } 260 } 261 262 return failures; 263 } 264 265 static int multiplyTests() { 266 int failures = 0; 267 268 BigDecimal ones[] = { 269 BigDecimal.valueOf(1, 0), 270 BigDecimal.valueOf(10, 1), 271 BigDecimal.valueOf(1000, 3), 272 BigDecimal.valueOf(100000000, 8), 273 }; 274 275 List<BigDecimal> values = new LinkedList<BigDecimal>(); 276 values.addAll(Arrays.asList(zeros)); 277 values.addAll(Arrays.asList(ones)); 278 279 for(BigDecimal zero1: zeros) { 280 for(BigDecimal value: values) { 281 BigDecimal expected = new BigDecimal(BigInteger.ZERO, 282 (int)Math.min(Math.max((long)zero1.scale()+value.scale(), 283 Integer.MIN_VALUE ), 284 Integer.MAX_VALUE ) ); 285 BigDecimal result; 286 287 if(! (result=zero1.multiply(value)).equals(expected) ) { 288 failures++; 289 System.err.println("For classic exact multiply, expected scale of " + 290 expected.scale() + "; got " + 291 result.scale() + "."); 292 } 293 294 if(! (result=zero1.multiply(value, MathContext.UNLIMITED)).equals(expected) ) { 295 failures++; 296 System.err.println("For UNLIMITED math context multiply," + 297 " expected scale of " + 298 expected.scale() + "; got " + 299 result.scale() + "."); 300 } 301 302 if(! (result=zero1.multiply(value, longEnough)).equals(expected) ) { 303 failures++; 304 System.err.println("For longEnough math context multiply," + 305 " expected scale of " + 306 expected.scale() + "; got " + 307 result.scale() + "."); 308 } 309 310 } 311 } 312 313 return failures; 314 } 315 316 static int divideTests() { 317 int failures = 0; 318 319 BigDecimal [] ones = { 320 BigDecimal.valueOf(1, 0), 321 BigDecimal.valueOf(10, -1), 322 BigDecimal.valueOf(100, -2), 323 BigDecimal.valueOf(1000, -3), 324 BigDecimal.valueOf(1000000, -5), 325 }; 326 327 for(BigDecimal one: ones) { 328 for(BigDecimal zero: zeros) { 329 BigDecimal expected = new BigDecimal(BigInteger.ZERO, 330 (int)Math.min(Math.max((long)zero.scale() - one.scale(), 331 Integer.MIN_VALUE ), 332 Integer.MAX_VALUE ) ); 333 BigDecimal result; 334 335 if(! (result=zero.divide(one)).equals(expected) ) { 336 failures++; 337 System.err.println("For classic exact divide, expected scale of " + 338 expected.scale() + "; got " + 339 result.scale() + "."); 340 } 341 342 if(! (result=zero.divide(one, MathContext.UNLIMITED)).equals(expected) ) { 343 failures++; 344 System.err.println("For UNLIMITED math context divide," + 345 " expected scale of " + 346 expected.scale() + "; got " + 347 result.scale() + "."); 348 } 349 350 if(! (result=zero.divide(one, longEnough)).equals(expected) ) { 351 failures++; 352 System.err.println("For longEnough math context divide," + 353 " expected scale of " + 354 expected.scale() + "; got " + 355 result.scale() + "."); 356 } 357 358 } 359 } 360 361 return failures; 362 } 363 364 static int setScaleTests() { 365 int failures = 0; 366 367 int scales[] = { 368 Integer.MIN_VALUE, 369 Integer.MIN_VALUE+1, 370 -10000000, 371 -3, 372 -2, 373 -1, 374 0, 375 1, 376 2, 377 3, 378 10, 379 10000000, 380 Integer.MAX_VALUE-1, 381 Integer.MAX_VALUE 382 }; 383 384 for(BigDecimal zero: zeros) { 385 for(int scale: scales) { 386 try { 387 BigDecimal bd = zero.setScale(scale); 388 } 389 catch (ArithmeticException e) { 390 failures++; 391 System.err.println("Exception when trying to set a scale of " + scale + 392 " on " + zero); 393 } 394 } 395 } 396 397 return failures; 398 } 399 400 static int toEngineeringStringTests() { 401 int failures = 0; 402 403 String [][] testCases = { 404 {"0E+10", "0.00E+12"}, 405 {"0E+9", "0E+9"}, 406 {"0E+8", "0.0E+9"}, 407 {"0E+7", "0.00E+9"}, 408 409 {"0E-10", "0.0E-9"}, 410 {"0E-9", "0E-9"}, 411 {"0E-8", "0.00E-6"}, 412 {"0E-7", "0.0E-6"}, 413 }; 414 415 for(String[] testCase: testCases) { 416 BigDecimal bd = new BigDecimal(testCase[0]); 417 String result = bd.toEngineeringString(); 418 419 if (!result.equals(testCase[1]) || 420 !bd.equals(new BigDecimal(result))) { 421 failures++; 422 System.err.println("From input ``" + testCase[0] + ",'' " + 423 " bad engineering string output ``" + result + 424 "''; expected ``" + testCase[1] + ".''"); 425 } 426 427 } 428 429 return failures; 430 } 431 432 static int ulpTests() { 433 int failures = 0; 434 435 for(BigDecimal zero: zeros) { 436 BigDecimal result; 437 BigDecimal expected = BigDecimal.valueOf(1, zero.scale()); 438 439 if (! (result=zero.ulp()).equals(expected) ) { 440 failures++; 441 System.err.println("Unexpected ulp value for zero value " + 442 zero + "; expected " + expected + 443 ", got " + result); 444 } 445 } 446 447 return failures; 448 } 449 450 public static void main(String argv[]) { 451 int failures = 0; 452 453 failures += addTests(); 454 failures += subtractTests(); 455 failures += multiplyTests(); 456 failures += divideTests(); 457 failures += setScaleTests(); 458 failures += toEngineeringStringTests(); 459 failures += ulpTests(); 460 461 if (failures > 0 ) { 462 throw new RuntimeException("Incurred " + failures + " failures" + 463 " testing the preservation of zero scales."); 464 } 465 } 466 }