Skip to content

Commit

Permalink
[flang][runtime] Fix edge cases with ROUND=UP/DOWN (#67508)
Browse files Browse the repository at this point in the history
When an unrepresentable nonzero real input value with a very small
exponent is currently being read in as zero, don't neglect
ROUND=UP/DOWN; return the least nonzero subnormal value instead when
appropriate.
  • Loading branch information
klausler committed Oct 16, 2023
1 parent af972f0 commit e35cb73
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 10 deletions.
3 changes: 2 additions & 1 deletion flang/lib/Decimal/binary-to-decimal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,8 @@ STREAM &BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Dump(STREAM &o) const {
if (isNegative_) {
o << '-';
}
o << "10**(" << exponent_ << ") * ...\n";
o << "10**(" << exponent_ << ") * ... (rounding "
<< static_cast<int>(rounding_) << ")\n";
for (int j{digits_}; --j >= 0;) {
std::string str{std::to_string(digit_[j])};
o << std::string(20 - str.size(), ' ') << str << " [" << j << ']';
Expand Down
30 changes: 21 additions & 9 deletions flang/lib/Decimal/decimal-to-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,20 @@ ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
flags |= Inexact;
}
if (fraction == 0 && guard <= oneHalf) {
return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
}
// The value is nonzero; normalize it.
while (fraction < topBit && expo > 1) {
--expo;
fraction = fraction * 2 + (guard >> (guardBits - 2));
guard = (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
if ((!isNegative && rounding == RoundUp) ||
(isNegative && rounding == RoundDown)) {
// round to minimum nonzero value
} else {
return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
}
} else {
// The value is nonzero; normalize it.
while (fraction < topBit && expo > 1) {
--expo;
fraction = fraction * 2 + (guard >> (guardBits - 2));
guard =
(((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
}
}
// Apply rounding
bool incr{false};
Expand Down Expand Up @@ -330,8 +337,13 @@ BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary() {
exponent_ += digits_ * log10Radix;
// Sanity checks for ridiculous exponents
static constexpr int crazy{2 * Real::decimalRange + log10Radix};
if (exponent_ < -crazy) { // underflow to +/-0.
return {Real{SignBit()}, Inexact};
if (exponent_ < -crazy) {
if ((!isNegative_ && rounding_ == RoundUp) ||
(isNegative_ && rounding_ == RoundDown)) {
return {Real{Raw{1} | SignBit()}}; // return least nonzero value
} else { // underflow to +/-0.
return {Real{SignBit()}, Inexact};
}
} else if (exponent_ > crazy) { // overflow to +/-Inf.
return {Real{Infinity()}, Overflow};
}
Expand Down

0 comments on commit e35cb73

Please sign in to comment.