< prev index next >

src/java.base/share/classes/java/math/BigDecimal.java

Print this page




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");
2227             case 0:
2228                 return valueOf(0L, scale()/2);
2229 
2230             default:
2231                 throw new AssertionError("Bad value from signum");
2232             }
2233         }
2234     }
2235 
2236     private boolean isPowerOfTen() {
2237         return BigInteger.ONE.equals(this.unscaledValue());
2238     }
2239 
2240     /**
2241      * For nonzero values, check numerical correctness properties of
2242      * the computed result for the chosen rounding mode.
2243      *
2244      * For the directed roundings, for DOWN and FLOOR, result^2 must
2245      * be {@code <=} the input and (result+ulp)^2 must be {@code >} the
2246      * input. Conversely, for UP and CEIL, result^2 must be {@code >=} the
2247      * input and (result-ulp)^2 must be {@code <} the input.
2248      */
2249     private boolean squareRootResultAssertions(BigDecimal result, MathContext mc) {
2250         if (result.signum() == 0) {
2251             return squareRootZeroResultAssertions(result, mc);
2252         } else {
2253             RoundingMode rm = mc.getRoundingMode();
2254             BigDecimal ulp = result.ulp();
2255             BigDecimal neighborUp   = result.add(ulp);
2256             // Make neighbor down accurate even for powers of ten
2257             if (this.isPowerOfTen()) {
2258                 ulp = ulp.divide(TEN);
2259             }
2260             BigDecimal neighborDown = result.subtract(ulp);
2261 
2262             // Both the starting value and result should be nonzero and positive.
2263             if (result.signum() != 1 ||
2264                 this.signum() != 1) {
2265                 return false;
2266             }
2267 
2268             switch (rm) {
2269             case DOWN:
2270             case FLOOR:
2271                 return
2272                     result.multiply(result).compareTo(this)         <= 0 &&
2273                     neighborUp.multiply(neighborUp).compareTo(this) > 0;


2274 
2275             case UP:
2276             case CEILING:
2277                 return
2278                     result.multiply(result).compareTo(this)             >= 0 &&
2279                     neighborDown.multiply(neighborDown).compareTo(this) < 0;



2280 
2281             case HALF_DOWN:
2282             case HALF_EVEN:
2283             case HALF_UP:
2284                 BigDecimal err = result.multiply(result).subtract(this).abs();
2285                 BigDecimal errUp = neighborUp.multiply(neighborUp).subtract(this);
2286                 BigDecimal errDown =  this.subtract(neighborDown.multiply(neighborDown));
2287                 // All error values should be positive so don't need to
2288                 // compare absolute values.
2289 
2290                 int err_comp_errUp = err.compareTo(errUp);
2291                 int err_comp_errDown = err.compareTo(errDown);
2292 
2293                 return
2294                     errUp.signum()   == 1 &&
2295                     errDown.signum() == 1 &&

2296 

2297                     err_comp_errUp   <= 0 &&
2298                     err_comp_errDown <= 0 &&

2299 

2300                     ((err_comp_errUp   == 0 ) ? err_comp_errDown < 0 : true) &&
2301                     ((err_comp_errDown == 0 ) ? err_comp_errUp   < 0 : true);

2302                 // && could check for digit conditions for ties too

2303 
2304             default: // Definition of UNNECESSARY already verified.
2305                 return true;
2306             }
2307         }
2308     }
2309 
2310     private boolean squareRootZeroResultAssertions(BigDecimal result, MathContext mc) {
2311         return this.compareTo(ZERO) == 0;
2312     }
2313 
2314     /**
2315      * Returns a {@code BigDecimal} whose value is
2316      * <code>(this<sup>n</sup>)</code>, The power is computed exactly, to
2317      * unlimited precision.
2318      *
2319      * <p>The parameter {@code n} must be in the range 0 through
2320      * 999999999, inclusive.  {@code ZERO.pow(0)} returns {@link
2321      * #ONE}.
2322      *




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 only 1/10
2216                         // as far way as the next larger at exponent
2217                         // boundaries. Test approx and *not* result to
2218                         // avoid having to detect an arbitrary power of ten.
2219                         if (approx.compareTo(ONE) == 0) {
2220                             ulp = ulp.multiply(ONE_TENTH);
2221                         }
2222                         result = result.subtract(ulp);
2223                     }
2224                     break;
2225 
2226                 case UP:
2227                 case CEILING:
2228                     // Check if too small
2229                     if (result.multiply(result).compareTo(this) < 0  ) {
2230                         result = result.add(result.ulp());
2231                     }
2232                     break;
2233 
2234                 default:
2235                     // Do nothing for half-way cases
2236                     // HALF_DOWN, HALF_EVEN, HALF_UP
2237                     // See fix-up in paper, up down by *1/2* ulp
2238                     
2239                     break;
2240                 }
2241 
2242             }
2243 
2244             // Test numerical properties at full precision before any
2245             // scale adjustments.
2246             assert squareRootResultAssertions(result, mc);
2247             if (result.scale() != preferredScale) {
2248                 // The preferred scale of an add is
2249                 // max(addend.scale(), augend.scale()). Therefore, if
2250                 // the scale of the result is first minimized using
2251                 // stripTrailingZeros(), adding a zero of the
2252                 // preferred scale rounding the correct precision will
2253                 // perform the proper scale vs precision tradeoffs.
2254                 result = result.stripTrailingZeros().
2255                     add(zeroWithFinalPreferredScale,
2256                         new MathContext(originalPrecision, RoundingMode.UNNECESSARY));
2257             }

2258             return result;
2259         } else {
2260             switch (signum) {
2261             case -1:
2262                 throw new ArithmeticException("Attempted square root " +
2263                                               "of negative BigDecimal");
2264             case 0:
2265                 return valueOf(0L, scale()/2);
2266 
2267             default:
2268                 throw new AssertionError("Bad value from signum");
2269             }
2270         }
2271     }
2272 
2273     private boolean isPowerOfTen() {
2274         return BigInteger.ONE.equals(this.unscaledValue());
2275     }
2276 
2277     /**
2278      * For nonzero values, check numerical correctness properties of
2279      * the computed result for the chosen rounding mode.
2280      *
2281      * For the directed roundings, for DOWN and FLOOR, result^2 must
2282      * be {@code <=} the input and (result+ulp)^2 must be {@code >} the
2283      * input. Conversely, for UP and CEIL, result^2 must be {@code >=} the
2284      * input and (result-ulp)^2 must be {@code <} the input.
2285      */
2286     private boolean squareRootResultAssertions(BigDecimal result, MathContext mc) {
2287         if (result.signum() == 0) {
2288             return squareRootZeroResultAssertions(result, mc);
2289         } else {
2290             RoundingMode rm = mc.getRoundingMode();
2291             BigDecimal ulp = result.ulp();
2292             BigDecimal neighborUp   = result.add(ulp);
2293             // Make neighbor down accurate even for powers of ten
2294             if (result.isPowerOfTen()) {
2295                 ulp = ulp.divide(TEN);
2296             }
2297             BigDecimal neighborDown = result.subtract(ulp);
2298 
2299             // Both the starting value and result should be nonzero and positive.
2300             if (result.signum() != 1 ||
2301                 this.signum() != 1) {
2302                 return false;
2303             }
2304 
2305             switch (rm) {
2306             case DOWN:
2307             case FLOOR:
2308                 assert
2309                     result.multiply(result).compareTo(this)         <= 0 &&
2310                     neighborUp.multiply(neighborUp).compareTo(this) > 0:
2311                 "Square of result out for bounds rounding " + rm;
2312                 return true;
2313 
2314             case UP:
2315             case CEILING:
2316                 assert
2317                     result.multiply(result).compareTo(this)             >= 0 &&
2318                     neighborDown.multiply(neighborDown).compareTo(this) < 0:
2319                 "Square of result out for bounds rounding " + rm;
2320                 return true;
2321 
2322 
2323             case HALF_DOWN:
2324             case HALF_EVEN:
2325             case HALF_UP:
2326                 BigDecimal err = result.multiply(result).subtract(this).abs();
2327                 BigDecimal errUp = neighborUp.multiply(neighborUp).subtract(this);
2328                 BigDecimal errDown =  this.subtract(neighborDown.multiply(neighborDown));
2329                 // All error values should be positive so don't need to
2330                 // compare absolute values.
2331 
2332                 int err_comp_errUp = err.compareTo(errUp);
2333                 int err_comp_errDown = err.compareTo(errDown);
2334 
2335                 assert
2336                     errUp.signum()   == 1 &&
2337                     errDown.signum() == 1 :
2338                 "Errors of neighbors squared don't have correct signs";
2339 
2340                 assert
2341                     err_comp_errUp   <= 0 &&
2342                     err_comp_errDown <= 0 :
2343                 "Computed square root has larger error than neighbors for " + rm;
2344 
2345                 assert
2346                     ((err_comp_errUp   == 0 ) ? err_comp_errDown < 0 : true) &&
2347                     ((err_comp_errDown == 0 ) ? err_comp_errUp   < 0 : true) :
2348                         "Incorrect error relationships";
2349                 // && could check for digit conditions for ties too
2350                 return true;
2351 
2352             default: // Definition of UNNECESSARY already verified.
2353                 return true;
2354             }
2355         }
2356     }
2357 
2358     private boolean squareRootZeroResultAssertions(BigDecimal result, MathContext mc) {
2359         return this.compareTo(ZERO) == 0;
2360     }
2361 
2362     /**
2363      * Returns a {@code BigDecimal} whose value is
2364      * <code>(this<sup>n</sup>)</code>, The power is computed exactly, to
2365      * unlimited precision.
2366      *
2367      * <p>The parameter {@code n} must be in the range 0 through
2368      * 999999999, inclusive.  {@code ZERO.pow(0)} returns {@link
2369      * #ONE}.
2370      *


< prev index next >