2187 // approx = 0.5 * (approx + fraction / approx) 2188 approx = ONE_HALF.multiply(approx.add(working.divide(approx, mcTmp), mcTmp)); 2189 guessPrecision *= 2; 2190 } while (guessPrecision < targetPrecision + 2); 2191 2192 BigDecimal result; 2193 RoundingMode targetRm = mc.getRoundingMode(); 2194 if (targetRm == RoundingMode.UNNECESSARY || originalPrecision == 0) { 2195 RoundingMode tmpRm = 2196 (targetRm == RoundingMode.UNNECESSARY) ? RoundingMode.DOWN : targetRm; 2197 MathContext mcTmp = new MathContext(targetPrecision, tmpRm); 2198 result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mcTmp); 2199 2200 // If result*result != this numerically, the square 2201 // root isn't exact 2202 if (this.subtract(result.multiply(result)).compareTo(ZERO) != 0) { 2203 throw new ArithmeticException("Computed square root not exact."); 2204 } 2205 } else { 2206 result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mc); 2207 } 2208 2209 if (result.scale() != preferredScale) { 2210 // The preferred scale of an add is 2211 // max(addend.scale(), augend.scale()). Therefore, if 2212 // the scale of the result is first minimized using 2213 // stripTrailingZeros(), adding a zero of the 2214 // preferred scale rounding the correct precision will 2215 // perform the proper scale vs precision tradeoffs. 2216 result = result.stripTrailingZeros(). 2217 add(zeroWithFinalPreferredScale, 2218 new MathContext(originalPrecision, RoundingMode.UNNECESSARY)); 2219 } 2220 assert squareRootResultAssertions(result, mc); 2221 return result; 2222 } else { 2223 switch (signum) { 2224 case -1: 2225 throw new ArithmeticException("Attempted square root " + 2226 "of negative BigDecimal"); | 2187 // approx = 0.5 * (approx + fraction / approx) 2188 approx = ONE_HALF.multiply(approx.add(working.divide(approx, mcTmp), mcTmp)); 2189 guessPrecision *= 2; 2190 } while (guessPrecision < targetPrecision + 2); 2191 2192 BigDecimal result; 2193 RoundingMode targetRm = mc.getRoundingMode(); 2194 if (targetRm == RoundingMode.UNNECESSARY || originalPrecision == 0) { 2195 RoundingMode tmpRm = 2196 (targetRm == RoundingMode.UNNECESSARY) ? RoundingMode.DOWN : targetRm; 2197 MathContext mcTmp = new MathContext(targetPrecision, tmpRm); 2198 result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mcTmp); 2199 2200 // If result*result != this numerically, the square 2201 // root isn't exact 2202 if (this.subtract(result.multiply(result)).compareTo(ZERO) != 0) { 2203 throw new ArithmeticException("Computed square root not exact."); 2204 } 2205 } else { 2206 result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mc); 2207 2208 switch (targetRm) { 2209 case DOWN: 2210 case FLOOR: 2211 // Check if too big 2212 if (result.multiply(result).compareTo(this) > 0 ) { 2213 BigDecimal ulp = ulp = result.ulp(); 2214 // Adjust increment down in case of 1.0 = 10^0 2215 // since the next smaller number is 1/10 2216 // closer than the next larger at exponent 2217 // boundaries. 2218 if (result.compareTo(ONE) == 0) { 2219 ulp = ulp.multiply(ONE_TENTH); 2220 } 2221 result = result.subtract(ulp); 2222 } 2223 break; 2224 2225 case UP: 2226 case CEILING: 2227 // Check if too small 2228 if (result.multiply(result).compareTo(this) < 0 ) { 2229 result = result.add(result.ulp()); 2230 } 2231 break; 2232 2233 default: 2234 // Do nothing for half-way cases 2235 // HALF_DOWN, HALF_EVEN, HALF_UP 2236 // See fix-up in paper, up down by *1/2* ulp 2237 break; 2238 } 2239 2240 } 2241 2242 if (result.scale() != preferredScale) { 2243 // The preferred scale of an add is 2244 // max(addend.scale(), augend.scale()). Therefore, if 2245 // the scale of the result is first minimized using 2246 // stripTrailingZeros(), adding a zero of the 2247 // preferred scale rounding the correct precision will 2248 // perform the proper scale vs precision tradeoffs. 2249 result = result.stripTrailingZeros(). 2250 add(zeroWithFinalPreferredScale, 2251 new MathContext(originalPrecision, RoundingMode.UNNECESSARY)); 2252 } 2253 assert squareRootResultAssertions(result, mc); 2254 return result; 2255 } else { 2256 switch (signum) { 2257 case -1: 2258 throw new ArithmeticException("Attempted square root " + 2259 "of negative BigDecimal"); |