diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index 16eb67f2e27c8..c71beb5262439 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -648,11 +648,10 @@ end only in function references, but not an explicit `INTRINSIC` statement, its name is not brought into other scopes by a `USE` statement. -* Should hexadecimal floating-point input editing apply any rounding? - F'2023 subclause 13.7.2.3.8 only discusses rounding in the context of - decimal-to-binary conversion; it would seem to not apply, and so - we don't round. This seems to be how the Intel Fortran compilers - behave. +* The subclause on rounding in formatted I/O (13.7.2.3.8 in F'2023) + only discusses rounding for decimal-to/from-binary conversions, + omitting any mention of rounding for hexadecimal conversions. + As other compilers do apply rounding, so does this one. ## De Facto Standard Features diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp index 6d4fa588cbf60..385a36174ed59 100644 --- a/flang/runtime/edit-input.cpp +++ b/flang/runtime/edit-input.cpp @@ -627,6 +627,31 @@ decimal::ConversionToBinaryResult ConvertHexadecimal( fraction <<= 1; --expo; } + // Rounding + bool increase{false}; + switch (rounding) { + case decimal::RoundNearest: // RN & RP + increase = roundingBit && (guardBit | ((int)fraction & 1)); + break; + case decimal::RoundUp: // RU + increase = !isNegative && (roundingBit | guardBit); + break; + case decimal::RoundDown: // RD + increase = isNegative && (roundingBit | guardBit); + break; + case decimal::RoundToZero: // RZ + break; + case decimal::RoundCompatible: // RC + increase = roundingBit != 0; + break; + } + if (increase) { + ++fraction; + if (fraction >> binaryPrecision) { + fraction >>= 1; + ++expo; + } + } } // Package & return result constexpr RawType significandMask{(one << RealType::significandBits) - 1}; @@ -637,9 +662,16 @@ decimal::ConversionToBinaryResult ConvertHexadecimal( expo = 0; // subnormal flags |= decimal::Underflow; } else if (expo >= RealType::maxExponent) { - expo = RealType::maxExponent; // +/-Inf - fraction = 0; - flags |= decimal::Overflow; + if (rounding == decimal::RoundToZero || + (rounding == decimal::RoundDown && !isNegative) || + (rounding == decimal::RoundUp && isNegative)) { + expo = RealType::maxExponent - 1; // +/-HUGE() + fraction = significandMask; + } else { + expo = RealType::maxExponent; // +/-Inf + fraction = 0; + flags |= decimal::Overflow; + } } else { fraction &= significandMask; // remove explicit normalization unless x87 }