Skip to content

Commit 853e2ca

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 a8bda0b commit 853e2ca

File tree

2 files changed

+50
-29
lines changed

2 files changed

+50
-29
lines changed

flang/runtime/edit-input.cpp

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -614,11 +614,23 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
614614
} else {
615615
break;
616616
}
617-
while (fraction >> binaryPrecision) {
618-
guardBit |= roundingBit;
619-
roundingBit = (int)fraction & 1;
620-
fraction >>= 1;
621-
++expo;
617+
if (fraction >> binaryPrecision) {
618+
while (fraction >> binaryPrecision) {
619+
guardBit |= roundingBit;
620+
roundingBit = (int)fraction & 1;
621+
fraction >>= 1;
622+
++expo;
623+
}
624+
// Consume excess digits
625+
while (*++p) {
626+
if (*p == '0') {
627+
} else if ((*p >= '1' && *p <= '9') || (*p >= 'A' && *p <= 'F')) {
628+
guardBit = 1;
629+
} else {
630+
break;
631+
}
632+
}
633+
break;
622634
}
623635
}
624636
if (fraction) {
@@ -633,31 +645,32 @@ decimal::ConversionToBinaryResult<binaryPrecision> ConvertHexadecimal(
633645
while (expo > 1 && !(fraction >> (binaryPrecision - 1))) {
634646
fraction <<= 1;
635647
--expo;
648+
guardBit = roundingBit = 0;
636649
}
637-
// Rounding
638-
bool increase{false};
639-
switch (rounding) {
640-
case decimal::RoundNearest: // RN & RP
641-
increase = roundingBit && (guardBit | ((int)fraction & 1));
642-
break;
643-
case decimal::RoundUp: // RU
644-
increase = !isNegative && (roundingBit | guardBit);
645-
break;
646-
case decimal::RoundDown: // RD
647-
increase = isNegative && (roundingBit | guardBit);
648-
break;
649-
case decimal::RoundToZero: // RZ
650-
break;
651-
case decimal::RoundCompatible: // RC
652-
increase = roundingBit != 0;
653-
break;
654-
}
655-
if (increase) {
656-
++fraction;
657-
if (fraction >> binaryPrecision) {
658-
fraction >>= 1;
659-
++expo;
660-
}
650+
}
651+
// Rounding
652+
bool increase{false};
653+
switch (rounding) {
654+
case decimal::RoundNearest: // RN & RP
655+
increase = roundingBit && (guardBit | ((int)fraction & 1));
656+
break;
657+
case decimal::RoundUp: // RU
658+
increase = !isNegative && (roundingBit | guardBit);
659+
break;
660+
case decimal::RoundDown: // RD
661+
increase = isNegative && (roundingBit | guardBit);
662+
break;
663+
case decimal::RoundToZero: // RZ
664+
break;
665+
case decimal::RoundCompatible: // RC
666+
increase = roundingBit != 0;
667+
break;
668+
}
669+
if (increase) {
670+
++fraction;
671+
if (fraction >> binaryPrecision) {
672+
fraction >>= 1;
673+
++expo;
661674
}
662675
}
663676
// 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)