1 /* 2 * Copyright (c) 2016, 2020, 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 package test.java.math.BigDecimal; 24 25 /* 26 * @test 27 * @bug 4851777 8233452 28 * @summary Tests of BigDecimal.sqrt(). 29 */ 30 31 import java.math.*; 32 import java.util.*; 33 34 import org.testng.Assert; 35 import org.testng.annotations.Test; 36 37 import static java.math.BigDecimal.ONE; 38 import static java.math.BigDecimal.TEN; 39 import static java.math.BigDecimal.ZERO; 40 import static java.math.BigDecimal.valueOf; 41 42 // Android-changed: Replace error counting with asserts. 43 public class SquareRootTests { 44 private static BigDecimal TWO = new BigDecimal(2); 45 46 /** 47 * The value 0.1, with a scale of 1. 48 */ 49 private static final BigDecimal ONE_TENTH = valueOf(1L, 1); 50 51 @Test negativeTests()52 public void negativeTests() { 53 for (long i = -10; i < 0; i++) { 54 for (int j = -5; j < 5; j++) { 55 try { 56 BigDecimal input = BigDecimal.valueOf(i, j); 57 BigDecimal result = input.sqrt(MathContext.DECIMAL64); 58 Assert.fail("Unexpected sqrt of negative: (" + 59 input + ").sqrt() = " + result ); 60 } catch (ArithmeticException e) { 61 ; // Expected 62 } 63 } 64 } 65 } 66 67 @Test zeroTests()68 public void zeroTests() { 69 for (int i = -100; i < 100; i++) { 70 BigDecimal expected = BigDecimal.valueOf(0L, i/2); 71 // These results are independent of rounding mode 72 compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.UNLIMITED), 73 expected, true, "zeros"); 74 75 compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.DECIMAL64), 76 expected, true, "zeros"); 77 } 78 } 79 80 /** 81 * Probe inputs with one digit of precision, 1 ... 9 and those 82 * values scaled by 10^-1, 0.1, ... 0.9. 83 */ 84 @Test oneDigitTests()85 public void oneDigitTests() { 86 int failures = 0; 87 88 List<BigDecimal> oneToNine = 89 List.of(ONE, TWO, valueOf(3), 90 valueOf(4), valueOf(5), valueOf(6), 91 valueOf(7), valueOf(8), valueOf(9)); 92 93 List<RoundingMode> modes = 94 List.of(RoundingMode.UP, RoundingMode.DOWN, 95 RoundingMode.CEILING, RoundingMode.FLOOR, 96 RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN); 97 98 for (int i = 1; i < 20; i++) { 99 for (RoundingMode rm : modes) { 100 for (BigDecimal bd : oneToNine) { 101 MathContext mc = new MathContext(i, rm); 102 103 compareSqrtImplementations(bd, mc); 104 bd = bd.multiply(ONE_TENTH); 105 compareSqrtImplementations(bd, mc); 106 } 107 } 108 } 109 110 // return failures; 111 } 112 113 /** 114 * Probe inputs with two digits of precision, (10 ... 99) and 115 * those values scaled by 10^-1 (1, ... 9.9) and scaled by 10^-2 116 * (0.1 ... 0.99). 117 */ 118 @Test twoDigitTests()119 public void twoDigitTests() { 120 int failures = 0; 121 122 List<RoundingMode> modes = 123 List.of(RoundingMode.UP, RoundingMode.DOWN, 124 RoundingMode.CEILING, RoundingMode.FLOOR, 125 RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN); 126 127 for (int i = 10; i < 100; i++) { 128 BigDecimal bd0 = BigDecimal.valueOf(i); 129 BigDecimal bd1 = bd0.multiply(ONE_TENTH); 130 BigDecimal bd2 = bd1.multiply(ONE_TENTH); 131 132 for (BigDecimal bd : List.of(bd0, bd1, bd2)) { 133 for (int precision = 1; i < 20; i++) { 134 for (RoundingMode rm : modes) { 135 MathContext mc = new MathContext(precision, rm); 136 compareSqrtImplementations(bd, mc); 137 } 138 } 139 } 140 } 141 142 // return failures; 143 } 144 compareSqrtImplementations(BigDecimal bd, MathContext mc)145 private static void compareSqrtImplementations(BigDecimal bd, MathContext mc) { 146 equalNumerically(BigSquareRoot.sqrt(bd, mc), 147 bd.sqrt(mc), "sqrt(" + bd + ") under " + mc); 148 } 149 150 /** 151 * sqrt(10^2N) is 10^N 152 * Both numerical value and representation should be verified 153 */ 154 @Test evenPowersOfTenTests()155 public void evenPowersOfTenTests() { 156 MathContext oneDigitExactly = new MathContext(1, RoundingMode.UNNECESSARY); 157 158 for (int scale = -100; scale <= 100; scale++) { 159 BigDecimal testValue = BigDecimal.valueOf(1, 2*scale); 160 BigDecimal expectedNumericalResult = BigDecimal.valueOf(1, scale); 161 162 BigDecimal result; 163 164 165 equalNumerically(expectedNumericalResult, 166 result = testValue.sqrt(MathContext.DECIMAL64), 167 "Even powers of 10, DECIMAL64"); 168 169 // Can round to one digit of precision exactly 170 equalNumerically(expectedNumericalResult, 171 result = testValue.sqrt(oneDigitExactly), 172 "even powers of 10, 1 digit"); 173 if (result.precision() > 1) { 174 Assert.fail("Excess precision for " + result); 175 } 176 // If rounding to more than one digit, do precision / scale checking... 177 } 178 } 179 180 @Test squareRootTwoTests()181 public void squareRootTwoTests() { 182 BigDecimal TWO = new BigDecimal(2); 183 184 // Square root of 2 truncated to 65 digits 185 BigDecimal highPrecisionRoot2 = 186 new BigDecimal("1.41421356237309504880168872420969807856967187537694807317667973799"); 187 188 RoundingMode[] modes = { 189 RoundingMode.UP, RoundingMode.DOWN, 190 RoundingMode.CEILING, RoundingMode.FLOOR, 191 RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN 192 }; 193 194 195 // For each interesting rounding mode, for precisions 1 to, say, 196 // 63 numerically compare TWO.sqrt(mc) to 197 // highPrecisionRoot2.round(mc) and the alternative internal high-precision 198 // implementation of square root. 199 for (RoundingMode mode : modes) { 200 for (int precision = 1; precision < 63; precision++) { 201 MathContext mc = new MathContext(precision, mode); 202 BigDecimal expected = highPrecisionRoot2.round(mc); 203 BigDecimal computed = TWO.sqrt(mc); 204 BigDecimal altComputed = BigSquareRoot.sqrt(TWO, mc); 205 206 equalNumerically(expected, computed, "sqrt(2)"); 207 equalNumerically(computed, altComputed, "computed & altComputed"); 208 } 209 } 210 } 211 212 @Test lowPrecisionPerfectSquares()213 public void lowPrecisionPerfectSquares() { 214 // For 5^2 through 9^2, if the input is rounded to one digit 215 // first before the root is computed, the wrong answer will 216 // result. Verify results and scale for different rounding 217 // modes and precisions. 218 long[][] squaresWithOneDigitRoot = {{ 4, 2}, 219 { 9, 3}, 220 {25, 5}, 221 {36, 6}, 222 {49, 7}, 223 {64, 8}, 224 {81, 9}}; 225 226 for (long[] squareAndRoot : squaresWithOneDigitRoot) { 227 BigDecimal square = new BigDecimal(squareAndRoot[0]); 228 BigDecimal expected = new BigDecimal(squareAndRoot[1]); 229 230 for (int scale = 0; scale <= 4; scale++) { 231 BigDecimal scaledSquare = square.setScale(scale, RoundingMode.UNNECESSARY); 232 int expectedScale = scale/2; 233 for (int precision = 0; precision <= 5; precision++) { 234 for (RoundingMode rm : RoundingMode.values()) { 235 MathContext mc = new MathContext(precision, rm); 236 BigDecimal computedRoot = scaledSquare.sqrt(mc); 237 238 equalNumerically(expected, computedRoot, "simple squares"); 239 240 int computedScale = computedRoot.scale(); 241 if (precision >= expectedScale + 1 && computedScale != expectedScale) { 242 Assert.fail(String.format("%s\tprecision=%d\trm=%s%n", 243 computedRoot, precision, rm) + 244 String.format("\t%s does not have expected scale of %d%n.", 245 computedRoot, expectedScale)); 246 } 247 } 248 } 249 } 250 } 251 } 252 253 /** 254 * Test around 3.9999 that the sqrt doesn't improperly round-up to 255 * a numerical value of 2. 256 */ 257 @Test almostFourRoundingDown()258 public void almostFourRoundingDown() { 259 int failures = 0; 260 BigDecimal nearFour = new BigDecimal("3.999999999999999999999999999999"); 261 262 // Sqrt is 1.9999... 263 264 for (int i = 1; i < 64; i++) { 265 MathContext mc = new MathContext(i, RoundingMode.FLOOR); 266 BigDecimal result = nearFour.sqrt(mc); 267 BigDecimal expected = BigSquareRoot.sqrt(nearFour, mc); 268 equalNumerically(expected, result, "near four rounding down"); 269 Assert.assertTrue(result.compareTo(TWO) < 0); 270 } 271 272 // return failures; 273 } 274 275 /** 276 * Test around 4.000...1 that the sqrt doesn't improperly 277 * round-down to a numerical value of 2. 278 */ 279 @Test 280 public void almostFourRoundingUp() { 281 int failures = 0; 282 BigDecimal nearFour = new BigDecimal("4.000000000000000000000000000001"); 283 284 // Sqrt is 2.0000....<non-zero digits> 285 286 for (int i = 1; i < 64; i++) { 287 MathContext mc = new MathContext(i, RoundingMode.CEILING); 288 BigDecimal result = nearFour.sqrt(mc); 289 BigDecimal expected = BigSquareRoot.sqrt(nearFour, mc); 290 equalNumerically(expected, result, "near four rounding up"); 291 Assert.assertTrue(result.compareTo(TWO) > 0); 292 } 293 294 // return failures; 295 } 296 297 @Test 298 public void nearTen() { 299 int failures = 0; 300 301 BigDecimal near10 = new BigDecimal("9.99999999999999999999"); 302 303 BigDecimal near10sq = near10.multiply(near10); 304 305 BigDecimal near10sq_ulp = near10sq.add(near10sq.ulp()); 306 307 for (int i = 10; i < 23; i++) { 308 MathContext mc = new MathContext(i, RoundingMode.HALF_EVEN); 309 310 equalNumerically(BigSquareRoot.sqrt(near10sq_ulp, mc), 311 near10sq_ulp.sqrt(mc), 312 "near 10 rounding half even"); 313 } 314 315 // return failures; 316 } 317 318 319 /* 320 * Probe for rounding failures near a power of ten, 1 = 10^0, 321 * where an ulp has a different size above and below the value. 322 */ 323 @Test 324 public void nearOne() { 325 int failures = 0; 326 327 BigDecimal near1 = new BigDecimal(".999999999999999999999"); 328 BigDecimal near1sq = near1.multiply(near1); 329 BigDecimal near1sq_ulp = near1sq.add(near1sq.ulp()); 330 331 for (int i = 10; i < 23; i++) { 332 for (RoundingMode rm : List.of(RoundingMode.HALF_EVEN, 333 RoundingMode.UP, 334 RoundingMode.DOWN )) { 335 MathContext mc = new MathContext(i, rm); 336 equalNumerically(BigSquareRoot.sqrt(near1sq_ulp, mc), 337 near1sq_ulp.sqrt(mc), 338 mc.toString()); 339 } 340 } 341 342 // return failures; 343 } 344 345 346 347 @Test 348 public void halfWay() { 349 int failures = 0; 350 351 /* 352 * Use enough digits that the exact result cannot be computed 353 * from the sqrt of a double. 354 */ 355 BigDecimal[] halfWayCases = { 356 // Odd next digit, truncate on HALF_EVEN 357 new BigDecimal("123456789123456789.5"), 358 359 // Even next digit, round up on HALF_EVEN 360 new BigDecimal("123456789123456788.5"), 361 }; 362 363 for (BigDecimal halfWayCase : halfWayCases) { 364 // Round result to next-to-last place 365 int precision = halfWayCase.precision() - 1; 366 BigDecimal square = halfWayCase.multiply(halfWayCase); 367 368 for (RoundingMode rm : List.of(RoundingMode.HALF_EVEN, 369 RoundingMode.HALF_UP, 370 RoundingMode.HALF_DOWN)) { 371 MathContext mc = new MathContext(precision, rm); 372 373 System.out.println("\nRounding mode " + rm); 374 System.out.println("\t" + halfWayCase.round(mc) + "\t" + halfWayCase); 375 System.out.println("\t" + BigSquareRoot.sqrt(square, mc)); 376 377 equalNumerically(/*square.sqrt(mc),*/ 378 BigSquareRoot.sqrt(square, mc), 379 halfWayCase.round(mc), 380 "Rounding halway " + rm); 381 } 382 } 383 384 // return failures; 385 } 386 387 private static void compare(BigDecimal a, BigDecimal b, boolean expected, String prefix) { 388 boolean result = a.equals(b); 389 Assert.assertEquals(result, expected, "Testing " + prefix + 390 "(" + a + ").compareTo(" + b + ") => " + result + 391 "\n\tExpected " + expected); 392 } 393 394 private static void equalNumerically(BigDecimal a, BigDecimal b, String prefix) { 395 compareNumerically(a, b, 0, prefix); 396 } 397 398 private static void compareNumerically(BigDecimal a, BigDecimal b, 399 int expected, String prefix) { 400 int result = a.compareTo(b); 401 Assert.assertEquals(result, expected, "Testing " + prefix + 402 "(" + a + ").compareTo(" + b + ") => " + result + 403 "\n\tExpected " + expected); 404 } 405 406 /** 407 * Alternative implementation of BigDecimal square root which uses 408 * higher-precision for a simpler set of termination conditions 409 * for the Newton iteration. 410 */ 411 private static class BigSquareRoot { 412 413 /** 414 * The value 0.5, with a scale of 1. 415 */ 416 private static final BigDecimal ONE_HALF = valueOf(5L, 1); 417 418 public static boolean isPowerOfTen(BigDecimal bd) { 419 return BigInteger.ONE.equals(bd.unscaledValue()); 420 } 421 422 public static BigDecimal square(BigDecimal bd) { 423 return bd.multiply(bd); 424 } 425 426 public static BigDecimal sqrt(BigDecimal bd, MathContext mc) { 427 int signum = bd.signum(); 428 if (signum == 1) { 429 /* 430 * The following code draws on the algorithm presented in 431 * "Properly Rounded Variable Precision Square Root," Hull and 432 * Abrham, ACM Transactions on Mathematical Software, Vol 11, 433 * No. 3, September 1985, Pages 229-237. 434 * 435 * The BigDecimal computational model differs from the one 436 * presented in the paper in several ways: first BigDecimal 437 * numbers aren't necessarily normalized, second many more 438 * rounding modes are supported, including UNNECESSARY, and 439 * exact results can be requested. 440 * 441 * The main steps of the algorithm below are as follows, 442 * first argument reduce the value to the numerical range 443 * [1, 10) using the following relations: 444 * 445 * x = y * 10 ^ exp 446 * sqrt(x) = sqrt(y) * 10^(exp / 2) if exp is even 447 * sqrt(x) = sqrt(y/10) * 10 ^((exp+1)/2) is exp is odd 448 * 449 * Then use Newton's iteration on the reduced value to compute 450 * the numerical digits of the desired result. 451 * 452 * Finally, scale back to the desired exponent range and 453 * perform any adjustment to get the preferred scale in the 454 * representation. 455 */ 456 457 // The code below favors relative simplicity over checking 458 // for special cases that could run faster. 459 460 int preferredScale = bd.scale()/2; 461 BigDecimal zeroWithFinalPreferredScale = 462 BigDecimal.valueOf(0L, preferredScale); 463 464 // First phase of numerical normalization, strip trailing 465 // zeros and check for even powers of 10. 466 BigDecimal stripped = bd.stripTrailingZeros(); 467 int strippedScale = stripped.scale(); 468 469 // Numerically sqrt(10^2N) = 10^N 470 if (isPowerOfTen(stripped) && 471 strippedScale % 2 == 0) { 472 BigDecimal result = BigDecimal.valueOf(1L, strippedScale/2); 473 if (result.scale() != preferredScale) { 474 // Adjust to requested precision and preferred 475 // scale as appropriate. 476 result = result.add(zeroWithFinalPreferredScale, mc); 477 } 478 return result; 479 } 480 481 // After stripTrailingZeros, the representation is normalized as 482 // 483 // unscaledValue * 10^(-scale) 484 // 485 // where unscaledValue is an integer with the mimimum 486 // precision for the cohort of the numerical value. To 487 // allow binary floating-point hardware to be used to get 488 // approximately a 15 digit approximation to the square 489 // root, it is helpful to instead normalize this so that 490 // the significand portion is to right of the decimal 491 // point by roughly (scale() - precision() + 1). 492 493 // Now the precision / scale adjustment 494 int scaleAdjust = 0; 495 int scale = stripped.scale() - stripped.precision() + 1; 496 if (scale % 2 == 0) { 497 scaleAdjust = scale; 498 } else { 499 scaleAdjust = scale - 1; 500 } 501 502 BigDecimal working = stripped.scaleByPowerOfTen(scaleAdjust); 503 504 assert // Verify 0.1 <= working < 10 505 ONE_TENTH.compareTo(working) <= 0 && working.compareTo(TEN) < 0; 506 507 // Use good ole' Math.sqrt to get the initial guess for 508 // the Newton iteration, good to at least 15 decimal 509 // digits. This approach does incur the cost of a 510 // 511 // BigDecimal -> double -> BigDecimal 512 // 513 // conversion cycle, but it avoids the need for several 514 // Newton iterations in BigDecimal arithmetic to get the 515 // working answer to 15 digits of precision. If many fewer 516 // than 15 digits were needed, it might be faster to do 517 // the loop entirely in BigDecimal arithmetic. 518 // 519 // (A double value might have as much many as 17 decimal 520 // digits of precision; it depends on the relative density 521 // of binary and decimal numbers at different regions of 522 // the number line.) 523 // 524 // (It would be possible to check for certain special 525 // cases to avoid doing any Newton iterations. For 526 // example, if the BigDecimal -> double conversion was 527 // known to be exact and the rounding mode had a 528 // low-enough precision, the post-Newton rounding logic 529 // could be applied directly.) 530 531 BigDecimal guess = new BigDecimal(Math.sqrt(working.doubleValue())); 532 int guessPrecision = 15; 533 int originalPrecision = mc.getPrecision(); 534 int targetPrecision; 535 536 // If an exact value is requested, it must only need 537 // about half of the input digits to represent since 538 // multiplying an N digit number by itself yield a (2N 539 // - 1) digit or 2N digit result. 540 if (originalPrecision == 0) { 541 targetPrecision = stripped.precision()/2 + 1; 542 } else { 543 targetPrecision = originalPrecision; 544 } 545 546 // When setting the precision to use inside the Newton 547 // iteration loop, take care to avoid the case where the 548 // precision of the input exceeds the requested precision 549 // and rounding the input value too soon. 550 BigDecimal approx = guess; 551 int workingPrecision = working.precision(); 552 // Use "2p + 2" property to guarantee enough 553 // intermediate precision so that a double-rounding 554 // error does not occur when rounded to the final 555 // destination precision. 556 int loopPrecision = 557 Math.max(2 * Math.max(targetPrecision, workingPrecision) + 2, 558 34); // Force at least two Netwon 559 // iterations on the Math.sqrt 560 // result. 561 do { 562 MathContext mcTmp = new MathContext(loopPrecision, RoundingMode.HALF_EVEN); 563 // approx = 0.5 * (approx + fraction / approx) 564 approx = ONE_HALF.multiply(approx.add(working.divide(approx, mcTmp), mcTmp)); 565 guessPrecision *= 2; 566 } while (guessPrecision < loopPrecision); 567 568 BigDecimal result; 569 RoundingMode targetRm = mc.getRoundingMode(); 570 if (targetRm == RoundingMode.UNNECESSARY || originalPrecision == 0) { 571 RoundingMode tmpRm = 572 (targetRm == RoundingMode.UNNECESSARY) ? RoundingMode.DOWN : targetRm; 573 MathContext mcTmp = new MathContext(targetPrecision, tmpRm); 574 result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mcTmp); 575 576 // If result*result != this numerically, the square 577 // root isn't exact 578 if (bd.subtract(square(result)).compareTo(ZERO) != 0) { 579 throw new ArithmeticException("Computed square root not exact."); 580 } 581 } else { 582 result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mc); 583 } 584 585 assert squareRootResultAssertions(bd, result, mc); 586 if (result.scale() != preferredScale) { 587 // The preferred scale of an add is 588 // max(addend.scale(), augend.scale()). Therefore, if 589 // the scale of the result is first minimized using 590 // stripTrailingZeros(), adding a zero of the 591 // preferred scale rounding the correct precision will 592 // perform the proper scale vs precision tradeoffs. 593 result = result.stripTrailingZeros(). 594 add(zeroWithFinalPreferredScale, 595 new MathContext(originalPrecision, RoundingMode.UNNECESSARY)); 596 } 597 return result; 598 } else { 599 switch (signum) { 600 case -1: 601 throw new ArithmeticException("Attempted square root " + 602 "of negative BigDecimal"); 603 case 0: 604 return valueOf(0L, bd.scale()/2); 605 606 default: 607 throw new AssertionError("Bad value from signum"); 608 } 609 } 610 } 611 612 /** 613 * For nonzero values, check numerical correctness properties of 614 * the computed result for the chosen rounding mode. 615 * 616 * For the directed roundings, for DOWN and FLOOR, result^2 must 617 * be {@code <=} the input and (result+ulp)^2 must be {@code >} the 618 * input. Conversely, for UP and CEIL, result^2 must be {@code >=} the 619 * input and (result-ulp)^2 must be {@code <} the input. 620 */ 621 private static boolean squareRootResultAssertions(BigDecimal input, BigDecimal result, MathContext mc) { 622 if (result.signum() == 0) { 623 return squareRootZeroResultAssertions(input, result, mc); 624 } else { 625 RoundingMode rm = mc.getRoundingMode(); 626 BigDecimal ulp = result.ulp(); 627 BigDecimal neighborUp = result.add(ulp); 628 // Make neighbor down accurate even for powers of ten 629 if (isPowerOfTen(result)) { 630 ulp = ulp.divide(TEN); 631 } 632 BigDecimal neighborDown = result.subtract(ulp); 633 634 // Both the starting value and result should be nonzero and positive. 635 if (result.signum() != 1 || 636 input.signum() != 1) { 637 return false; 638 } 639 640 switch (rm) { 641 case DOWN: 642 case FLOOR: 643 assert 644 square(result).compareTo(input) <= 0 && 645 square(neighborUp).compareTo(input) > 0: 646 "Square of result out for bounds rounding " + rm; 647 return true; 648 649 case UP: 650 case CEILING: 651 assert 652 square(result).compareTo(input) >= 0 : 653 "Square of result too small rounding " + rm; 654 655 assert 656 square(neighborDown).compareTo(input) < 0 : 657 "Square of down neighbor too large rounding " + rm + "\n" + 658 "\t input: " + input + "\t neighborDown: " + neighborDown +"\t sqrt: " + result + 659 "\t" + mc; 660 return true; 661 662 663 case HALF_DOWN: 664 case HALF_EVEN: 665 case HALF_UP: 666 BigDecimal err = square(result).subtract(input).abs(); 667 BigDecimal errUp = square(neighborUp).subtract(input); 668 BigDecimal errDown = input.subtract(square(neighborDown)); 669 // All error values should be positive so don't need to 670 // compare absolute values. 671 672 int err_comp_errUp = err.compareTo(errUp); 673 int err_comp_errDown = err.compareTo(errDown); 674 675 assert 676 errUp.signum() == 1 && 677 errDown.signum() == 1 : 678 "Errors of neighbors squared don't have correct signs"; 679 680 // At least one of these must be true, but not both 681 // assert 682 // err_comp_errUp <= 0 : "Upper neighbor is closer than result: " + rm + 683 // "\t" + input + "\t result" + result; 684 // assert 685 // err_comp_errDown <= 0 : "Lower neighbor is closer than result: " + rm + 686 // "\t" + input + "\t result " + result + "\t lower neighbor: " + neighborDown; 687 688 assert 689 ((err_comp_errUp == 0 ) ? err_comp_errDown < 0 : true) && 690 ((err_comp_errDown == 0 ) ? err_comp_errUp < 0 : true) : 691 "Incorrect error relationships"; 692 // && could check for digit conditions for ties too 693 return true; 694 695 default: // Definition of UNNECESSARY already verified. 696 return true; 697 } 698 } 699 } 700 701 private static boolean squareRootZeroResultAssertions(BigDecimal input, 702 BigDecimal result, 703 MathContext mc) { 704 return input.compareTo(ZERO) == 0; 705 } 706 } 707 } 708 709