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