mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8314169: Combine related RoundingMode logic in j.text.DigitList
Reviewed-by: naoto
This commit is contained in:
parent
808bb1f7bc
commit
96778dd549
1 changed files with 85 additions and 102 deletions
|
@ -112,13 +112,22 @@ final class DigitList implements Cloneable {
|
||||||
* Return true if the represented number is zero.
|
* Return true if the represented number is zero.
|
||||||
*/
|
*/
|
||||||
boolean isZero() {
|
boolean isZero() {
|
||||||
for (int i=0; i < count; ++i) {
|
return !nonZeroAfterIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if there exists a non-zero digit in the digit list
|
||||||
|
* from the given index until the end.
|
||||||
|
*/
|
||||||
|
private boolean nonZeroAfterIndex(int index) {
|
||||||
|
for (int i=index; i < count; ++i) {
|
||||||
if (digits[i] != '0') {
|
if (digits[i] != '0') {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the rounding mode
|
* Set the rounding mode
|
||||||
|
@ -190,9 +199,7 @@ final class DigitList implements Cloneable {
|
||||||
|
|
||||||
StringBuilder temp = getStringBuilder();
|
StringBuilder temp = getStringBuilder();
|
||||||
temp.append(digits, 0, count);
|
temp.append(digits, 0, count);
|
||||||
for (int i = count; i < decimalAt; ++i) {
|
temp.append("0".repeat(Math.max(0, decimalAt - count)));
|
||||||
temp.append('0');
|
|
||||||
}
|
|
||||||
return Long.parseLong(temp.toString());
|
return Long.parseLong(temp.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,6 +399,17 @@ final class DigitList implements Cloneable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Round the representation to the given number of digits.
|
||||||
|
* @param maximumDigits The maximum number of digits to be shown.
|
||||||
|
*
|
||||||
|
* Upon return, count will be less than or equal to maximumDigits.
|
||||||
|
*/
|
||||||
|
private void roundInt(int maximumDigits) {
|
||||||
|
// Integers do not need to worry about double rounding
|
||||||
|
round(maximumDigits, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Round the representation to the given number of digits.
|
* Round the representation to the given number of digits.
|
||||||
* @param maximumDigits The maximum number of digits to be shown.
|
* @param maximumDigits The maximum number of digits to be shown.
|
||||||
|
@ -408,25 +426,8 @@ final class DigitList implements Cloneable {
|
||||||
// Round up if appropriate.
|
// Round up if appropriate.
|
||||||
if (maximumDigits >= 0 && maximumDigits < count) {
|
if (maximumDigits >= 0 && maximumDigits < count) {
|
||||||
if (shouldRoundUp(maximumDigits, alreadyRounded, valueExactAsDecimal)) {
|
if (shouldRoundUp(maximumDigits, alreadyRounded, valueExactAsDecimal)) {
|
||||||
// Rounding up involved incrementing digits from LSD to MSD.
|
// Rounding can adjust the max digits
|
||||||
// In most cases this is simple, but in a worst case situation
|
maximumDigits = roundUp(maximumDigits);
|
||||||
// (9999..99) we have to adjust the decimalAt value.
|
|
||||||
for (;;) {
|
|
||||||
--maximumDigits;
|
|
||||||
if (maximumDigits < 0) {
|
|
||||||
// We have all 9's, so we increment to a single digit
|
|
||||||
// of one and adjust the exponent.
|
|
||||||
digits[0] = '1';
|
|
||||||
++decimalAt;
|
|
||||||
maximumDigits = 0; // Adjust the count
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
++digits[maximumDigits];
|
|
||||||
if (digits[maximumDigits] <= '9') break;
|
|
||||||
// digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
|
|
||||||
}
|
|
||||||
++maximumDigits; // Increment for use as count
|
|
||||||
}
|
}
|
||||||
count = maximumDigits;
|
count = maximumDigits;
|
||||||
|
|
||||||
|
@ -508,95 +509,45 @@ final class DigitList implements Cloneable {
|
||||||
|
|
||||||
switch(roundingMode) {
|
switch(roundingMode) {
|
||||||
case UP:
|
case UP:
|
||||||
for (int i=maximumDigits; i<count; ++i) {
|
return nonZeroAfterIndex(maximumDigits);
|
||||||
if (digits[i] != '0') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DOWN:
|
case DOWN:
|
||||||
break;
|
break;
|
||||||
case CEILING:
|
case CEILING:
|
||||||
for (int i=maximumDigits; i<count; ++i) {
|
return nonZeroAfterIndex(maximumDigits) && !isNegative;
|
||||||
if (digits[i] != '0') {
|
|
||||||
return !isNegative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FLOOR:
|
case FLOOR:
|
||||||
for (int i=maximumDigits; i<count; ++i) {
|
return nonZeroAfterIndex(maximumDigits) && isNegative;
|
||||||
if (digits[i] != '0') {
|
|
||||||
return isNegative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HALF_UP:
|
case HALF_UP:
|
||||||
case HALF_DOWN:
|
case HALF_DOWN:
|
||||||
|
case HALF_EVEN:
|
||||||
|
// Above tie, round up for all cases
|
||||||
if (digits[maximumDigits] > '5') {
|
if (digits[maximumDigits] > '5') {
|
||||||
// Value is above tie ==> must round up
|
|
||||||
return true;
|
return true;
|
||||||
} else if (digits[maximumDigits] == '5') {
|
// At tie, consider UP, DOWN, and EVEN logic
|
||||||
// Digit at rounding position is a '5'. Tie cases.
|
} else if (digits[maximumDigits] == '5' ) {
|
||||||
if (maximumDigits != (count - 1)) {
|
// Rounding position is the last index, there are 3 Cases.
|
||||||
// There are remaining digits. Above tie => must round up
|
if (maximumDigits == (count - 1)) {
|
||||||
return true;
|
// When exact, consider specific contract logic
|
||||||
} else {
|
|
||||||
// Digit at rounding position is the last one !
|
|
||||||
if (valueExactAsDecimal) {
|
if (valueExactAsDecimal) {
|
||||||
// Exact binary representation. On the tie.
|
return (roundingMode == RoundingMode.HALF_UP) ||
|
||||||
// Apply rounding given by roundingMode.
|
(roundingMode == RoundingMode.HALF_EVEN
|
||||||
return roundingMode == RoundingMode.HALF_UP;
|
&& (maximumDigits > 0) && (digits[maximumDigits - 1] % 2 != 0));
|
||||||
|
// If already rounded, do not round again, otherwise round up
|
||||||
} else {
|
} else {
|
||||||
// Not an exact binary representation.
|
|
||||||
// Digit sequence either rounded up or truncated.
|
|
||||||
// Round up only if it was truncated.
|
|
||||||
return !alreadyRounded;
|
return !alreadyRounded;
|
||||||
}
|
}
|
||||||
}
|
// Rounding position is not the last index
|
||||||
}
|
// If any further digits have a non-zero value, round up
|
||||||
// Digit at rounding position is < '5' ==> no round up.
|
|
||||||
// Just let do the default, which is no round up (thus break).
|
|
||||||
break;
|
|
||||||
case HALF_EVEN:
|
|
||||||
// Implement IEEE half-even rounding
|
|
||||||
if (digits[maximumDigits] > '5') {
|
|
||||||
return true;
|
|
||||||
} else if (digits[maximumDigits] == '5' ) {
|
|
||||||
if (maximumDigits == (count - 1)) {
|
|
||||||
// the rounding position is exactly the last index :
|
|
||||||
if (alreadyRounded)
|
|
||||||
// If FloatingDecimal rounded up (value was below tie),
|
|
||||||
// then we should not round up again.
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!valueExactAsDecimal)
|
|
||||||
// Otherwise if the digits don't represent exact value,
|
|
||||||
// value was above tie and FloatingDecimal truncated
|
|
||||||
// digits to tie. We must round up.
|
|
||||||
return true;
|
|
||||||
else {
|
|
||||||
// This is an exact tie value, and FloatingDecimal
|
|
||||||
// provided all of the exact digits. We thus apply
|
|
||||||
// HALF_EVEN rounding rule.
|
|
||||||
return ((maximumDigits > 0) &&
|
|
||||||
(digits[maximumDigits-1] % 2 != 0));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Rounds up if it gives a non null digit after '5'
|
return nonZeroAfterIndex(maximumDigits+1);
|
||||||
for (int i=maximumDigits+1; i<count; ++i) {
|
|
||||||
if (digits[i] != '0')
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Below tie, do not round up for all cases
|
||||||
break;
|
break;
|
||||||
case UNNECESSARY:
|
case UNNECESSARY:
|
||||||
for (int i=maximumDigits; i<count; ++i) {
|
if (nonZeroAfterIndex(maximumDigits)) {
|
||||||
if (digits[i] != '0') {
|
|
||||||
throw new ArithmeticException(
|
throw new ArithmeticException(
|
||||||
"Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
|
"Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert false;
|
assert false;
|
||||||
|
@ -605,6 +556,33 @@ final class DigitList implements Cloneable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Round the digit list up numerically.
|
||||||
|
* This involves incrementing digits from the LSD to the MSD.
|
||||||
|
* @param maximumDigits The maximum number of digits to be shown.
|
||||||
|
* @return The new maximum digits after rounding.
|
||||||
|
*/
|
||||||
|
private int roundUp(int maximumDigits) {
|
||||||
|
do {
|
||||||
|
--maximumDigits;
|
||||||
|
/*
|
||||||
|
* We have exhausted the max digits while attempting to round up
|
||||||
|
* from the LSD to the MSD. This implies a value of all 9's. As such,
|
||||||
|
* adjust representation to a single digit of one and increment the exponent.
|
||||||
|
*/
|
||||||
|
if (maximumDigits < 0) {
|
||||||
|
digits[0] = '1';
|
||||||
|
++decimalAt;
|
||||||
|
maximumDigits = 0; // Adjust the count
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++digits[maximumDigits];
|
||||||
|
}
|
||||||
|
while (digits[maximumDigits] > '9');
|
||||||
|
|
||||||
|
return ++maximumDigits; // Increment for use as count
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility routine to set the value of the digit list from a long
|
* Utility routine to set the value of the digit list from a long
|
||||||
*/
|
*/
|
||||||
|
@ -649,12 +627,16 @@ final class DigitList implements Cloneable {
|
||||||
decimalAt = MAX_COUNT - left;
|
decimalAt = MAX_COUNT - left;
|
||||||
// Don't copy trailing zeros. We are guaranteed that there is at
|
// Don't copy trailing zeros. We are guaranteed that there is at
|
||||||
// least one non-zero digit, so we don't have to check lower bounds.
|
// least one non-zero digit, so we don't have to check lower bounds.
|
||||||
for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
|
right = MAX_COUNT - 1;
|
||||||
;
|
while (digits[right] == '0') {
|
||||||
|
--right;
|
||||||
|
}
|
||||||
count = right - left + 1;
|
count = right - left + 1;
|
||||||
System.arraycopy(digits, left, digits, 0, count);
|
System.arraycopy(digits, left, digits, 0, count);
|
||||||
}
|
}
|
||||||
if (maximumDigits > 0) round(maximumDigits, false, true);
|
if (maximumDigits > 0) {
|
||||||
|
roundInt(maximumDigits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -692,13 +674,14 @@ final class DigitList implements Cloneable {
|
||||||
s.getChars(0, len, digits, 0);
|
s.getChars(0, len, digits, 0);
|
||||||
|
|
||||||
decimalAt = len;
|
decimalAt = len;
|
||||||
int right;
|
int right = len - 1;
|
||||||
for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
|
while (right >= 0 && digits[right] == '0') {
|
||||||
;
|
--right;
|
||||||
|
}
|
||||||
count = right + 1;
|
count = right + 1;
|
||||||
|
|
||||||
if (maximumDigits > 0) {
|
if (maximumDigits > 0) {
|
||||||
round(maximumDigits, false, true);
|
roundInt(maximumDigits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue