Skip to content

Commit e35cb73

Browse files
authored
[flang][runtime] Fix edge cases with ROUND=UP/DOWN (#67508)
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.
1 parent af972f0 commit e35cb73

File tree

2 files changed

+23
-10
lines changed

2 files changed

+23
-10
lines changed

flang/lib/Decimal/binary-to-decimal.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,8 @@ STREAM &BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Dump(STREAM &o) const {
373373
if (isNegative_) {
374374
o << '-';
375375
}
376-
o << "10**(" << exponent_ << ") * ...\n";
376+
o << "10**(" << exponent_ << ") * ... (rounding "
377+
<< static_cast<int>(rounding_) << ")\n";
377378
for (int j{digits_}; --j >= 0;) {
378379
std::string str{std::to_string(digit_[j])};
379380
o << std::string(20 - str.size(), ' ') << str << " [" << j << ']';

flang/lib/Decimal/decimal-to-binary.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -257,13 +257,20 @@ ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
257257
flags |= Inexact;
258258
}
259259
if (fraction == 0 && guard <= oneHalf) {
260-
return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
261-
}
262-
// The value is nonzero; normalize it.
263-
while (fraction < topBit && expo > 1) {
264-
--expo;
265-
fraction = fraction * 2 + (guard >> (guardBits - 2));
266-
guard = (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
260+
if ((!isNegative && rounding == RoundUp) ||
261+
(isNegative && rounding == RoundDown)) {
262+
// round to minimum nonzero value
263+
} else {
264+
return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
265+
}
266+
} else {
267+
// The value is nonzero; normalize it.
268+
while (fraction < topBit && expo > 1) {
269+
--expo;
270+
fraction = fraction * 2 + (guard >> (guardBits - 2));
271+
guard =
272+
(((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
273+
}
267274
}
268275
// Apply rounding
269276
bool incr{false};
@@ -330,8 +337,13 @@ BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary() {
330337
exponent_ += digits_ * log10Radix;
331338
// Sanity checks for ridiculous exponents
332339
static constexpr int crazy{2 * Real::decimalRange + log10Radix};
333-
if (exponent_ < -crazy) { // underflow to +/-0.
334-
return {Real{SignBit()}, Inexact};
340+
if (exponent_ < -crazy) {
341+
if ((!isNegative_ && rounding_ == RoundUp) ||
342+
(isNegative_ && rounding_ == RoundDown)) {
343+
return {Real{Raw{1} | SignBit()}}; // return least nonzero value
344+
} else { // underflow to +/-0.
345+
return {Real{SignBit()}, Inexact};
346+
}
335347
} else if (exponent_ > crazy) { // overflow to +/-Inf.
336348
return {Real{Infinity()}, Overflow};
337349
}

0 commit comments

Comments
 (0)