1 /*
   2  * Copyright (c) 2016, 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
  27  * @summary Tests of BigDecimal.sqrt().
  28  */
  29 
  30 import java.math.*;
  31 import java.util.*;
  32 
  33 public class SquareRootTests {
  34 
  35     public static void main(String... args) {
  36         int failures = 0;
  37 
  38         failures += negativeTests();
  39         failures += zeroTests();
  40         failures += evenPowersOfTenTests();
  41         failures += squareRootTwoTests();
  42 
  43         // Add trickier rounding cases -- try to find examples of
  44 
  45             // When setting the precision to use inside the loop, take
  46             // care to avoid the case where the precision of the input
  47             // exceeds the requested precision and rounding the input
  48             // value too soon.
  49 
  50 
  51         if (failures > 0 ) {
  52             throw new RuntimeException("Incurred " + failures + " failures" +
  53                                        " testing BigDecimal.sqrt().");
  54         }
  55     }
  56 
  57     private static int negativeTests() {
  58         int failures = 0;
  59 
  60         for (long i = -10; i < 0; i++) {
  61             for (int j = -5; j < 5; j++) {
  62                 try {
  63                     BigDecimal input = BigDecimal.valueOf(i, j);
  64                     BigDecimal result = input.sqrt(MathContext.DECIMAL64);
  65                     System.err.println("Unexpected sqrt of negative: (" +
  66                                        input + ").sqrt()  = " + result );
  67                     failures += 1;
  68                 } catch (ArithmeticException e) {
  69                     ; // Expected
  70                 }
  71             }
  72         }
  73         
  74         return failures;
  75     }
  76 
  77     private static int zeroTests() {
  78         int failures = 0;
  79 
  80         for (int i = -100; i < 100; i++) {
  81             BigDecimal expected = BigDecimal.valueOf(0L, i/2);
  82             // These results are independent of rounding mode
  83             failures += compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.UNLIMITED),
  84                                 expected, true, "zeros");
  85 
  86             failures += compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.DECIMAL64),
  87                                 expected, true, "zeros");
  88         }
  89 
  90         return failures;
  91     }
  92 
  93     /**
  94      * sqrt(10^2N) is 10^N
  95      * Both numerical value and representation should be verified
  96      */
  97     private static int evenPowersOfTenTests() {
  98         int failures = 0;
  99         MathContext oneDigitExactly = new MathContext(1, RoundingMode.UNNECESSARY);
 100 
 101         for (int scale = -100; scale <= 100; scale++) {
 102             BigDecimal testValue       = BigDecimal.valueOf(1, 2*scale);
 103             BigDecimal expectedNumericalResult = BigDecimal.valueOf(1, scale);
 104 
 105             BigDecimal result;
 106 
 107 
 108             failures += equalNumerically(expectedNumericalResult,
 109                                            result = testValue.sqrt(MathContext.DECIMAL64),
 110                                            "Even powers of 10, DECIMAL64");
 111 
 112             // Can round to one digit of precision exactly
 113             failures += equalNumerically(expectedNumericalResult,
 114                                            result = testValue.sqrt(oneDigitExactly),
 115                                            "even powers of 10, 1 digit");
 116             if (result.precision() > 1) {
 117                 failures += 1;
 118                 System.err.println("Excess precision for " + result);
 119             }
 120                 
 121 
 122             // If rounding to more than one digit, do precision / scale checking...
 123 
 124         }
 125 
 126         return failures;
 127     }
 128 
 129     private static int squareRootTwoTests() {
 130         int failures = 0;
 131         BigDecimal TWO = new BigDecimal(2);
 132 
 133         // Square root of 2 truncated to 65 digits
 134         BigDecimal highPrecisionRoot2 =
 135             new BigDecimal("1.41421356237309504880168872420969807856967187537694807317667973799");
 136 
 137 
 138         RoundingMode[] modes = {
 139             RoundingMode.UP,       RoundingMode.DOWN,
 140             RoundingMode.CEILING, RoundingMode.FLOOR,
 141             RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN
 142         };
 143 
 144         // For each iteresting rounding mode, for precisions 1 to, say
 145         // 63 numerically compare TWO.sqrt(mc) to
 146         // highPrecisionRoot2.round(mc)
 147         
 148         for (RoundingMode mode : modes) {
 149             for (int precision = 1; precision < 63; precision++) {
 150                 MathContext mc = new MathContext(precision, mode);
 151                 BigDecimal expected = highPrecisionRoot2.round(mc); 
 152                 BigDecimal computed = TWO.sqrt(mc);
 153 
 154                 equalNumerically(expected, computed, "sqrt(2)");
 155             }
 156         }
 157 
 158         return failures;
 159     }
 160 
 161 
 162 
 163     private static int compare(BigDecimal a, BigDecimal b, boolean expected, String prefix) {
 164         boolean result = a.equals(b);
 165         int failed = (result==expected) ? 0 : 1;
 166         if (failed == 1) {
 167             System.err.println("Testing " + prefix + 
 168                                "(" + a + ").compareTo(" + b + ") => " + result +
 169                                "\n\tExpected " + expected);
 170         }
 171         return failed;
 172     }
 173 
 174     private static int equalNumerically(BigDecimal a, BigDecimal b,
 175                                         String prefix) {
 176         return compareNumerically(a, b, 0, prefix);
 177     }
 178 
 179 
 180     private static int compareNumerically(BigDecimal a, BigDecimal b,
 181                                           int expected, String prefix) {
 182         int result = a.compareTo(b);
 183         int failed = (result==expected) ? 0 : 1;
 184         if (failed == 1) {
 185             System.err.println("Testing " + prefix + 
 186                                "(" + a + ").compareTo(" + b + ") => " + result +
 187                                "\n\tExpected " + expected);
 188         }
 189         return failed;
 190     }
 191 
 192 }