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