Skip to content

Commit 953236d

Browse files
committed
[flang][runtime] Round hex REAL input correctly with excess digits
Excess hexadecimal digits were too significant for rounding purposes, leading to inappropriate rounding away from zero for some modes.
1 parent 60fa2b0 commit 953236d

File tree

2 files changed

+49
-29
lines changed

2 files changed

+49
-29
lines changed

flang/runtime/edit-input.cpp

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -612,11 +612,22 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
612612
} else {
613613
break;
614614
}
615-
while (fraction >> binaryPrecision) {
616-
guardBit |= roundingBit;
617-
roundingBit = (int)fraction & 1;
618-
fraction >>= 1;
619-
++expo;
615+
if (fraction >> binaryPrecision) {
616+
while (fraction >> binaryPrecision) {
617+
guardBit |= roundingBit;
618+
roundingBit = (int)fraction & 1;
619+
fraction >>= 1;
620+
++expo;
621+
}
622+
// Consume excess digits
623+
for (; *p; ++p) {
624+
if ((*p >= '1' && *p <= '9') || (*p >= 'A' && *p <= 'F')) {
625+
guardBit = 1;
626+
} else if (*p != '0') {
627+
break;
628+
}
629+
}
630+
break;
620631
}
621632
}
622633
if (fraction) {
@@ -631,31 +642,32 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
631642
while (expo > 1 && !(fraction >> (binaryPrecision - 1))) {
632643
fraction <<= 1;
633644
--expo;
645+
guardBit = roundingBit = 0;
634646
}
635-
// Rounding
636-
bool increase{false};
637-
switch (rounding) {
638-
case decimal::RoundNearest: // RN & RP
639-
increase = roundingBit && (guardBit | ((int)fraction & 1));
640-
break;
641-
case decimal::RoundUp: // RU
642-
increase = !isNegative && (roundingBit | guardBit);
643-
break;
644-
case decimal::RoundDown: // RD
645-
increase = isNegative && (roundingBit | guardBit);
646-
break;
647-
case decimal::RoundToZero: // RZ
648-
break;
649-
case decimal::RoundCompatible: // RC
650-
increase = roundingBit != 0;
651-
break;
652-
}
653-
if (increase) {
654-
++fraction;
655-
if (fraction >> binaryPrecision) {
656-
fraction >>= 1;
657-
++expo;
658-
}
647+
}
648+
// Rounding
649+
bool increase{false};
650+
switch (rounding) {
651+
case decimal::RoundNearest: // RN & RP
652+
increase = roundingBit && (guardBit | ((int)fraction & 1));
653+
break;
654+
case decimal::RoundUp: // RU
655+
increase = !isNegative && (roundingBit | guardBit);
656+
break;
657+
case decimal::RoundDown: // RD
658+
increase = isNegative && (roundingBit | guardBit);
659+
break;
660+
case decimal::RoundToZero: // RZ
661+
break;
662+
case decimal::RoundCompatible: // RC
663+
increase = roundingBit != 0;
664+
break;
665+
}
666+
if (increase) {
667+
++fraction;
668+
if (fraction >> binaryPrecision) {
669+
fraction >>= 1;
670+
++expo;
659671
}
660672
}
661673
// Package & return result

flang/unittests/Runtime/NumericalFormatTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,14 @@ TEST(IOApiTests, EditDoubleInputValues) {
902902
0}, // max finite
903903
{"(EX22.0)", "0X.8P1025 ", 0x7ff0000000000000, ovf}, // +Inf
904904
{"(EX22.0)", "-0X.8P1025 ", 0xfff0000000000000, ovf}, // -Inf
905+
{"(RC,EX22.0)", "0X1.0000000000000P0 ", 0x3ff0000000000000, 0},
906+
{"(RC,EX22.0)", "0X1.00000000000008P0 ", 0x3ff0000000000001, 0},
907+
{"(RC,EX22.0)", "0X1.000000000000008P0 ", 0x3ff0000000000000, 0},
908+
{"(RC,EX22.0)", "0X1.00000000000004P0 ", 0x3ff0000000000000, 0},
909+
{"(RC,EX22.0)", "0X.80000000000000P1 ", 0x3ff0000000000000, 0},
910+
{"(RC,EX22.0)", "0X.80000000000004P1 ", 0x3ff0000000000001, 0},
911+
{"(RC,EX22.0)", "0X.800000000000004P1 ", 0x3ff0000000000000, 0},
912+
{"(RC,EX22.0)", "0X.80000000000002P1 ", 0x3ff0000000000000, 0},
905913
{"(RZ,F7.0)", " 2.e308", 0x7fefffffffffffff, 0}, // +HUGE()
906914
{"(RD,F7.0)", " 2.e308", 0x7fefffffffffffff, 0}, // +HUGE()
907915
{"(RU,F7.0)", " 2.e308", 0x7ff0000000000000, ovf}, // +Inf

0 commit comments

Comments
 (0)