@@ -1011,13 +1011,17 @@ std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
10111011 return os;
10121012}
10131013
1014- // Returns true if negate_value is true and the next character on the
1015- // input stream is a plus or minus sign. In that case we also set the fail bit
1016- // on the stream and set the value to the zero value for its type.
1014+ // Encodes whether a leading sign has been seen, and if so which one.
1015+ enum class LeadingSign { None, Plus, Minus };
1016+
1017+ // Returns true if leading_sign is either Plus or Minus, and the next character
1018+ // on the input stream is a plus or minus sign. In that case we also set the
1019+ // fail bit on the stream and set the value to the zero value for its type.
10171020template <typename T, typename Traits>
1018- inline bool RejectParseDueToLeadingSign (std::istream& is, bool negate_value,
1021+ inline bool RejectParseDueToLeadingSign (std::istream& is,
1022+ LeadingSign leading_sign,
10191023 HexFloat<T, Traits>& value) {
1020- if (negate_value ) {
1024+ if (leading_sign != LeadingSign::None ) {
10211025 auto next_char = is.peek ();
10221026 if (next_char == ' -' || next_char == ' +' ) {
10231027 // Fail the parse. Emulate standard behaviour by setting the value to
@@ -1032,22 +1036,24 @@ inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value,
10321036
10331037// Parses a floating point number from the given stream and stores it into the
10341038// value parameter.
1035- // If negate_value is true then the number may not have a leading minus or
1036- // plus, and if it successfully parses, then the number is negated before
1037- // being stored into the value parameter.
1039+ // If leading_sign is Plus or Minus, then the number may not have a leading
1040+ // minus or plus. If it successfully parses, and the leading sign was Minus,
1041+ // then the number is negated before being stored into the value parameter.
10381042// If the value cannot be correctly parsed or overflows the target floating
10391043// point type, then set the fail bit on the stream.
10401044// TODO(dneto): Promise C++11 standard behavior in how the value is set in
10411045// the error case, but only after all target platforms implement it correctly.
10421046// In particular, the Microsoft C++ runtime appears to be out of spec.
10431047template <typename T, typename Traits>
1044- inline std::istream& ParseNormalFloat (std::istream& is, bool negate_value,
1048+ inline std::istream& ParseNormalFloat (std::istream& is,
1049+ LeadingSign leading_sign,
10451050 HexFloat<T, Traits>& value) {
1046- if (RejectParseDueToLeadingSign (is, negate_value , value)) {
1051+ if (RejectParseDueToLeadingSign (is, leading_sign , value)) {
10471052 return is;
10481053 }
10491054 T val;
10501055 is >> val;
1056+ const bool negate_value = leading_sign == LeadingSign::Minus;
10511057 if (negate_value) {
10521058 val = -val;
10531059 }
@@ -1070,8 +1076,9 @@ inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value,
10701076// This will parse the float as it were a 32-bit floating point number,
10711077// and then round it down to fit into a Float16 value.
10721078// The number is rounded towards zero.
1073- // If negate_value is true then the number may not have a leading minus or
1074- // plus, and if it successfully parses, then the number is negated before
1079+ // If leading_sign is Plus or Minus, then the number may not have a leading
1080+ // minus or plus. If it successfully parses, and the leading sign was Minus,
1081+ // then the number is negated before being stored into the value parameter.
10751082// being stored into the value parameter.
10761083// If the value cannot be correctly parsed or overflows the target floating
10771084// point type, then set the fail bit on the stream.
@@ -1081,11 +1088,11 @@ inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value,
10811088template <>
10821089inline std::istream&
10831090ParseNormalFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
1084- std::istream& is, bool negate_value ,
1091+ std::istream& is, LeadingSign leading_sign ,
10851092 HexFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>& value) {
10861093 // First parse as a 32-bit float.
10871094 HexFloat<FloatProxy<float >> float_val (0 .0f );
1088- ParseNormalFloat (is, negate_value , float_val);
1095+ ParseNormalFloat (is, leading_sign , float_val);
10891096
10901097 // Then convert to 16-bit float, saturating at infinities, and
10911098 // rounding toward zero.
@@ -1106,11 +1113,11 @@ ParseNormalFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
11061113template <>
11071114inline std::istream&
11081115ParseNormalFloat<FloatProxy<BFloat16>, HexFloatTraits<FloatProxy<BFloat16>>>(
1109- std::istream& is, bool negate_value ,
1116+ std::istream& is, LeadingSign leading_sign ,
11101117 HexFloat<FloatProxy<BFloat16>, HexFloatTraits<FloatProxy<BFloat16>>>&
11111118 value) {
11121119 HexFloat<FloatProxy<float >> float_val (0 .0f );
1113- ParseNormalFloat (is, negate_value , float_val);
1120+ ParseNormalFloat (is, leading_sign , float_val);
11141121
11151122 float_val.castTo (value, round_direction::kToZero );
11161123
@@ -1125,8 +1132,8 @@ ParseNormalFloat<FloatProxy<BFloat16>, HexFloatTraits<FloatProxy<BFloat16>>>(
11251132// This will parse the float as it were a 32-bit floating point number,
11261133// and then round it down to fit into a Float8_E4M3 value.
11271134// The number is rounded towards zero.
1128- // If negate_value is true then the number may not have a leading minus or
1129- // plus, and if it successfully parses, then the number is negated before
1135+ // If leading_sign is Plus or Minus, then the number may not have a leading
1136+ // minus or plus. If it successfully parses, and the leading sign was Minus,
11301137// being stored into the value parameter.
11311138// If the value cannot be correctly parsed or overflows the target floating
11321139// point type, then set the fail bit on the stream.
@@ -1136,12 +1143,12 @@ ParseNormalFloat<FloatProxy<BFloat16>, HexFloatTraits<FloatProxy<BFloat16>>>(
11361143template <>
11371144inline std::istream& ParseNormalFloat<FloatProxy<Float8_E4M3>,
11381145 HexFloatTraits<FloatProxy<Float8_E4M3>>>(
1139- std::istream& is, bool negate_value ,
1146+ std::istream& is, LeadingSign leading_sign ,
11401147 HexFloat<FloatProxy<Float8_E4M3>, HexFloatTraits<FloatProxy<Float8_E4M3>>>&
11411148 value) {
11421149 // First parse as a 32-bit float.
11431150 HexFloat<FloatProxy<float >> float_val (0 .0f );
1144- ParseNormalFloat (is, negate_value , float_val);
1151+ ParseNormalFloat (is, leading_sign , float_val);
11451152
11461153 if (float_val.value ().getAsFloat () > 448 .0f ) {
11471154 is.setstate (std::ios_base::failbit);
@@ -1162,8 +1169,8 @@ inline std::istream& ParseNormalFloat<FloatProxy<Float8_E4M3>,
11621169// This will parse the float as it were a Float8_E5M2 floating point number,
11631170// and then round it down to fit into a Float16 value.
11641171// The number is rounded towards zero.
1165- // If negate_value is true then the number may not have a leading minus or
1166- // plus, and if it successfully parses, then the number is negated before
1172+ // If leading_sign is Plus or Minus, then the number may not have a leading
1173+ // minus or plus. If it successfully parses, and the leading sign was Minus,
11671174// being stored into the value parameter.
11681175// If the value cannot be correctly parsed or overflows the target floating
11691176// point type, then set the fail bit on the stream.
@@ -1173,12 +1180,12 @@ inline std::istream& ParseNormalFloat<FloatProxy<Float8_E4M3>,
11731180template <>
11741181inline std::istream& ParseNormalFloat<FloatProxy<Float8_E5M2>,
11751182 HexFloatTraits<FloatProxy<Float8_E5M2>>>(
1176- std::istream& is, bool negate_value ,
1183+ std::istream& is, LeadingSign leading_sign ,
11771184 HexFloat<FloatProxy<Float8_E5M2>, HexFloatTraits<FloatProxy<Float8_E5M2>>>&
11781185 value) {
11791186 // First parse as a 32-bit float.
11801187 HexFloat<FloatProxy<float >> float_val (0 .0f );
1181- ParseNormalFloat (is, negate_value , float_val);
1188+ ParseNormalFloat (is, leading_sign , float_val);
11821189
11831190 // Then convert to Float8_E5M2 float, saturating at infinities, and
11841191 // rounding toward zero.
@@ -1270,14 +1277,19 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
12701277 }
12711278
12721279 auto next_char = is.peek ();
1273- bool negate_value = false ;
12741280
1275- if (next_char != ' -' && next_char != ' 0' ) {
1276- return ParseNormalFloat (is, negate_value, value);
1281+ auto leading_sign = LeadingSign::None;
1282+
1283+ if (next_char != ' -' && next_char != ' 0' && next_char != ' +' ) {
1284+ return ParseNormalFloat (is, LeadingSign::None, value);
12771285 }
12781286
12791287 if (next_char == ' -' ) {
1280- negate_value = true ;
1288+ leading_sign = LeadingSign::Minus;
1289+ is.get ();
1290+ next_char = is.peek ();
1291+ } else if (next_char == ' +' ) {
1292+ leading_sign = LeadingSign::Plus;
12811293 is.get ();
12821294 next_char = is.peek ();
12831295 }
@@ -1287,12 +1299,12 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
12871299 auto maybe_hex_start = is.peek ();
12881300 if (maybe_hex_start != ' x' && maybe_hex_start != ' X' ) {
12891301 is.unget ();
1290- return ParseNormalFloat (is, negate_value , value);
1302+ return ParseNormalFloat (is, leading_sign , value);
12911303 } else {
12921304 is.get (); // Throw away the 'x';
12931305 }
12941306 } else {
1295- return ParseNormalFloat (is, negate_value , value);
1307+ return ParseNormalFloat (is, leading_sign , value);
12961308 }
12971309
12981310 // This "looks" like a hex-float so treat it as one.
@@ -1508,7 +1520,8 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
15081520 }
15091521
15101522 uint_type output_bits = static_cast <uint_type>(
1511- static_cast <uint_type>(negate_value ? 1 : 0 ) << HF::top_bit_left_shift);
1523+ static_cast <uint_type>(leading_sign == LeadingSign::Minus ? 1 : 0 )
1524+ << HF::top_bit_left_shift);
15121525 output_bits |= fraction;
15131526
15141527 uint_type shifted_exponent = static_cast <uint_type>(
0 commit comments