• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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