From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 38F1E3858C20; Mon, 14 Aug 2023 17:10:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 38F1E3858C20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1692033044; bh=J+rWo+22VgumBDfvQaoNm39l0ghVC1xBUHEqMOk+0tI=; h=From:To:Subject:Date:From; b=fFOoUOzGd6tOWeH7H6/Dr8sWRgT68sq0M/QyqIXxN+NM0QzvBQddwRfNCHOSJjrec VsAuV+3pb6todtapjnRk8plRpuvpFo7fvGstbwMGLe8+Wtgn2erNc44dEvMnjSwbq5 OCkIY3yjDmUWf1Ew9JwbcGSo5EKjvH6+27xsUIxk= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r14-3202] libstdc++: Avoid problematic use of log10 in std::format [PR110860] X-Act-Checkin: gcc X-Git-Author: Paul Dreik X-Git-Refname: refs/heads/master X-Git-Oldrev: 882af290c137dfab5d99b88e6dbecc5e75d85a0b X-Git-Newrev: 2d2b05f0691799f03062bf5c436462f14cad3e7c Message-Id: <20230814171044.38F1E3858C20@sourceware.org> Date: Mon, 14 Aug 2023 17:10:44 +0000 (GMT) List-Id: https://gcc.gnu.org/g:2d2b05f0691799f03062bf5c436462f14cad3e7c commit r14-3202-g2d2b05f0691799f03062bf5c436462f14cad3e7c Author: Paul Dreik Date: Mon Aug 14 15:42:33 2023 +0100 libstdc++: Avoid problematic use of log10 in std::format [PR110860] If abs(__v) is smaller than one, the result will be of the form 0.xxxxx. It is only if the magnitude is large that more digits are needed before the decimal dot. This uses frexp instead of log10 which should be less expensive and have sufficient precision for the desired purpose. It removes the problematic cases where log10 will be negative or not fit in an int. Signed-off-by: Paul Dreik libstdc++-v3/ChangeLog: PR libstdc++/110860 * include/std/format (__formatter_fp::format): Use frexp instead of log10. Diff: --- libstdc++-v3/include/std/format | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index f4520ff3f746..7ea0377ec715 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -1490,14 +1490,23 @@ namespace __format // If the buffer is too small it's probably because of a large // precision, or a very large value in fixed format. size_t __guess = 8 + __prec; - if (__fmt == chars_format::fixed && __v != 0) // +ddd.prec + if (__fmt == chars_format::fixed) // +ddd.prec { - if constexpr (is_same_v<_Fp, float>) - __guess += __builtin_log10f(__v < 0.0f ? -__v : __v); - else if constexpr (is_same_v<_Fp, double>) - __guess += __builtin_log10(__v < 0.0 ? -__v : __v); - else if constexpr (is_same_v<_Fp, long double>) - __guess += __builtin_log10l(__v < 0.0l ? -__v : __v); + if constexpr (is_same_v<_Fp, float> || is_same_v<_Fp, double> + || is_same_v<_Fp, long double>) + { + // The number of digits to the left of the decimal point + // is floor(log10(max(abs(__v),1)))+1 + int __exp{}; + if constexpr (is_same_v<_Fp, float>) + __builtin_frexpf(__v, &__exp); + else if constexpr (is_same_v<_Fp, double>) + __builtin_frexp(__v, &__exp); + else if constexpr (is_same_v<_Fp, long double>) + __builtin_frexpl(__v, &__exp); + if (__exp > 0) + __guess += 1U + __exp * 4004U / 13301U; // log10(2) approx. + } else __guess += numeric_limits<_Fp>::max_exponent10; }