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