--- old/src/java.base/share/classes/java/math/BigDecimal.java 2019-11-27 06:27:39.784000000 -0800 +++ new/src/java.base/share/classes/java/math/BigDecimal.java 2019-11-27 06:27:39.528000000 -0800 @@ -2204,8 +2204,46 @@ } } else { result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mc); + + switch (targetRm) { + case DOWN: + case FLOOR: + // Check if too big + if (result.multiply(result).compareTo(this) > 0 ) { + BigDecimal ulp = ulp = result.ulp(); + // Adjust increment down in case of 1.0 = 10^0 + // since the next smaller number is only 1/10 + // as far way as the next larger at exponent + // boundaries. Test approx and *not* result to + // avoid having to detect an arbitrary power of ten. + if (approx.compareTo(ONE) == 0) { + ulp = ulp.multiply(ONE_TENTH); + } + result = result.subtract(ulp); + } + break; + + case UP: + case CEILING: + // Check if too small + if (result.multiply(result).compareTo(this) < 0 ) { + result = result.add(result.ulp()); + } + break; + + default: + // Do nothing for half-way cases + // HALF_DOWN, HALF_EVEN, HALF_UP + // See fix-up in paper, up down by *1/2* ulp + + break; + } + } + // Test numerical properties at full precision before any + // scale adjustments. + assert squareRootResultAssertions(result, mc); if (result.scale() != preferredScale) { // The preferred scale of an add is // max(addend.scale(), augend.scale()). Therefore, if @@ -2217,7 +2255,6 @@ add(zeroWithFinalPreferredScale, new MathContext(originalPrecision, RoundingMode.UNNECESSARY)); } - assert squareRootResultAssertions(result, mc); return result; } else { switch (signum) { @@ -2254,7 +2291,7 @@ BigDecimal ulp = result.ulp(); BigDecimal neighborUp = result.add(ulp); // Make neighbor down accurate even for powers of ten - if (this.isPowerOfTen()) { + if (result.isPowerOfTen()) { ulp = ulp.divide(TEN); } BigDecimal neighborDown = result.subtract(ulp); @@ -2268,15 +2305,20 @@ switch (rm) { case DOWN: case FLOOR: - return + assert result.multiply(result).compareTo(this) <= 0 && - neighborUp.multiply(neighborUp).compareTo(this) > 0; + neighborUp.multiply(neighborUp).compareTo(this) > 0: + "Square of result out for bounds rounding " + rm; + return true; case UP: case CEILING: - return + assert result.multiply(result).compareTo(this) >= 0 && - neighborDown.multiply(neighborDown).compareTo(this) < 0; + neighborDown.multiply(neighborDown).compareTo(this) < 0: + "Square of result out for bounds rounding " + rm; + return true; + case HALF_DOWN: case HALF_EVEN: @@ -2290,16 +2332,22 @@ int err_comp_errUp = err.compareTo(errUp); int err_comp_errDown = err.compareTo(errDown); - return + assert errUp.signum() == 1 && - errDown.signum() == 1 && + errDown.signum() == 1 : + "Errors of neighbors squared don't have correct signs"; + assert err_comp_errUp <= 0 && - err_comp_errDown <= 0 && + err_comp_errDown <= 0 : + "Computed square root has larger error than neighbors for " + rm; + assert ((err_comp_errUp == 0 ) ? err_comp_errDown < 0 : true) && - ((err_comp_errDown == 0 ) ? err_comp_errUp < 0 : true); + ((err_comp_errDown == 0 ) ? err_comp_errUp < 0 : true) : + "Incorrect error relationships"; // && could check for digit conditions for ties too + return true; default: // Definition of UNNECESSARY already verified. return true;