From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 444C9385480D; Mon, 31 Oct 2022 11:23:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 444C9385480D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1667215434; bh=gD3B63QpGPqQCnuv85QuT8WGHg+mTO+EsQJNYh1+EPI=; h=From:To:Subject:Date:From; b=ECwzope7DDw6juPHnj3rkHSeb1oiwb8ouN0PKBLN2M0T6e8b5PjDfvBBdbUn1uUF6 j5dBPxesMPWYoHoTfKY/TdfWU3EjmLtoBbxcKmYHaQjhph16TOgwn+0AJiczcmTZA2 G0uya5ct9x3rg3DhNiLEu+8fF4SsE7Vp21bzwKUI= From: "jakub at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug libstdc++/107468] New: std::from_chars doesn't always round to nearest Date: Mon, 31 Oct 2022 11:23:46 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: libstdc++ X-Bugzilla-Version: 13.0 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: jakub at gcc dot gnu.org X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D107468 Bug ID: 107468 Summary: std::from_chars doesn't always round to nearest Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: jakub at gcc dot gnu.org Target Milestone: --- #include #include #include #include int main() { float f; char buf[] =3D "3.355447e+07"; fesetround(FE_DOWNWARD); auto [ptr, ec] =3D std::from_chars(buf, buf + sizeof (buf) - 1, f, std::chars_format::scientific); char buf2[128]; auto [ptr2, ec2] =3D std::to_chars(buf2, buf2 + 128, f, std::chars_format::fixed); std::cout << std::string_view(buf2, ptr2 - buf2) << std::endl; } 33554470 isn't representable in IEEE single, only 33554468 and 33554472 are, the former is 0x1.000012p+25 and the latter is 0x1.000014p+25 and the latter has 0 as the least significant digit. So, round to even should be 33554472 and that is what happens without the fesetround(FE_DOWNWARD). When fast_float isn't used, floating_from_chars.cc temporarily overrides the rounding to nearest, but when it is used, it doesn't. In most cases it is fine, because fast_float usually computes the mantissa = and exponent in integral code. But it has two exceptions for this I think. One is the fast path: // Next is Clinger's fast path. if (binary_format::min_exponent_fast_path() <=3D pns.exponent && pns.exponent <=3D binary_format::max_exponent_fast_path() && pns.mantissa <=3Dbinary_format::max_mantissa_fast_p ath() && !pns.too_many_digits) { value =3D T(pns.mantissa); if (pns.exponent < 0) { value =3D value / binary_format::exact_power_of_ten(-pns.exponent); } else { value =3D value * binary_format::exact_power_of_ten(pns.expon= ent); } if (pns.negative) { value =3D -value; } return answer; } I'm afraid we need to temporarily override rounding to nearest around the multiplications in there. And the other one is: T b; to_float(false, am_b, b); adjusted_mantissa theor =3D to_extended_halfway(b); where I think we don't really need it but I don't understand the point of jumping through the floating point format, it encodes am_b into an integer, memcpys it to float/double (in to_float), then immediately memcpys it back = to an integer (in to_extended called from to_extended_halfway) and then unpack= s it with some adjustments.=