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 main(String... args)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 += lowPrecisionPerfectSquares(); 43 44 if (failures > 0 ) { 45 throw new RuntimeException("Incurred " + failures + " failures" + 46 " testing BigDecimal.sqrt()."); 47 } 48 } 49 negativeTests()50 private static int negativeTests() { 51 int failures = 0; 52 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 System.err.println("Unexpected sqrt of negative: (" + 59 input + ").sqrt() = " + result ); 60 failures += 1; 61 } catch (ArithmeticException e) { 62 ; // Expected 63 } 64 } 65 } 66 67 return failures; 68 } 69 zeroTests()70 private static int zeroTests() { 71 int failures = 0; 72 73 for (int i = -100; i < 100; i++) { 74 BigDecimal expected = BigDecimal.valueOf(0L, i/2); 75 // These results are independent of rounding mode 76 failures += compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.UNLIMITED), 77 expected, true, "zeros"); 78 79 failures += compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.DECIMAL64), 80 expected, true, "zeros"); 81 } 82 83 return failures; 84 } 85 86 /** 87 * sqrt(10^2N) is 10^N 88 * Both numerical value and representation should be verified 89 */ evenPowersOfTenTests()90 private static int evenPowersOfTenTests() { 91 int failures = 0; 92 MathContext oneDigitExactly = new MathContext(1, RoundingMode.UNNECESSARY); 93 94 for (int scale = -100; scale <= 100; scale++) { 95 BigDecimal testValue = BigDecimal.valueOf(1, 2*scale); 96 BigDecimal expectedNumericalResult = BigDecimal.valueOf(1, scale); 97 98 BigDecimal result; 99 100 101 failures += equalNumerically(expectedNumericalResult, 102 result = testValue.sqrt(MathContext.DECIMAL64), 103 "Even powers of 10, DECIMAL64"); 104 105 // Can round to one digit of precision exactly 106 failures += equalNumerically(expectedNumericalResult, 107 result = testValue.sqrt(oneDigitExactly), 108 "even powers of 10, 1 digit"); 109 if (result.precision() > 1) { 110 failures += 1; 111 System.err.println("Excess precision for " + result); 112 } 113 114 115 // If rounding to more than one digit, do precision / scale checking... 116 117 } 118 119 return failures; 120 } 121 squareRootTwoTests()122 private static int squareRootTwoTests() { 123 int failures = 0; 124 BigDecimal TWO = new BigDecimal(2); 125 126 // Square root of 2 truncated to 65 digits 127 BigDecimal highPrecisionRoot2 = 128 new BigDecimal("1.41421356237309504880168872420969807856967187537694807317667973799"); 129 130 131 RoundingMode[] modes = { 132 RoundingMode.UP, RoundingMode.DOWN, 133 RoundingMode.CEILING, RoundingMode.FLOOR, 134 RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN 135 }; 136 137 // For each iteresting rounding mode, for precisions 1 to, say 138 // 63 numerically compare TWO.sqrt(mc) to 139 // highPrecisionRoot2.round(mc) 140 141 for (RoundingMode mode : modes) { 142 for (int precision = 1; precision < 63; precision++) { 143 MathContext mc = new MathContext(precision, mode); 144 BigDecimal expected = highPrecisionRoot2.round(mc); 145 BigDecimal computed = TWO.sqrt(mc); 146 147 equalNumerically(expected, computed, "sqrt(2)"); 148 } 149 } 150 151 return failures; 152 } 153 lowPrecisionPerfectSquares()154 private static int lowPrecisionPerfectSquares() { 155 int failures = 0; 156 157 // For 5^2 through 9^2, if the input is rounded to one digit 158 // first before the root is computed, the wrong answer will 159 // result. Verify results and scale for different rounding 160 // modes and precisions. 161 long[][] squaresWithOneDigitRoot = {{ 4, 2}, 162 { 9, 3}, 163 {25, 5}, 164 {36, 6}, 165 {49, 7}, 166 {64, 8}, 167 {81, 9}}; 168 169 for (long[] squareAndRoot : squaresWithOneDigitRoot) { 170 BigDecimal square = new BigDecimal(squareAndRoot[0]); 171 BigDecimal expected = new BigDecimal(squareAndRoot[1]); 172 173 for (int scale = 0; scale <= 4; scale++) { 174 BigDecimal scaledSquare = square.setScale(scale, RoundingMode.UNNECESSARY); 175 int expectedScale = scale/2; 176 for (int precision = 0; precision <= 5; precision++) { 177 for (RoundingMode rm : RoundingMode.values()) { 178 MathContext mc = new MathContext(precision, rm); 179 BigDecimal computedRoot = scaledSquare.sqrt(mc); 180 failures += equalNumerically(expected, computedRoot, "simple squares"); 181 int computedScale = computedRoot.scale(); 182 if (precision >= expectedScale + 1 && 183 computedScale != expectedScale) { 184 System.err.printf("%s\tprecision=%d\trm=%s%n", 185 computedRoot.toString(), precision, rm); 186 failures++; 187 System.err.printf("\t%s does not have expected scale of %d%n.", 188 computedRoot, expectedScale); 189 } 190 } 191 } 192 } 193 } 194 195 return failures; 196 } 197 compare(BigDecimal a, BigDecimal b, boolean expected, String prefix)198 private static int compare(BigDecimal a, BigDecimal b, boolean expected, String prefix) { 199 boolean result = a.equals(b); 200 int failed = (result==expected) ? 0 : 1; 201 if (failed == 1) { 202 System.err.println("Testing " + prefix + 203 "(" + a + ").compareTo(" + b + ") => " + result + 204 "\n\tExpected " + expected); 205 } 206 return failed; 207 } 208 equalNumerically(BigDecimal a, BigDecimal b, String prefix)209 private static int equalNumerically(BigDecimal a, BigDecimal b, 210 String prefix) { 211 return compareNumerically(a, b, 0, prefix); 212 } 213 214 compareNumerically(BigDecimal a, BigDecimal b, int expected, String prefix)215 private static int compareNumerically(BigDecimal a, BigDecimal b, 216 int expected, String prefix) { 217 int result = a.compareTo(b); 218 int failed = (result==expected) ? 0 : 1; 219 if (failed == 1) { 220 System.err.println("Testing " + prefix + 221 "(" + a + ").compareTo(" + b + ") => " + result + 222 "\n\tExpected " + expected); 223 } 224 return failed; 225 } 226 227 } 228