This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4602. Incorrect lower bound for the default floating-point representation

Section: 28.2.2 [charconv.to.chars] Status: New Submitter: Victor Zverovich Opened: 2026-07-04 Last modified: 2026-07-04

Priority: Not Prioritized

View other active issues in [charconv.to.chars].

View all other issues in [charconv.to.chars].

View all issues with New status.

Discussion:

P3505R4 (See also isocpp.org/P3505R4) unintentionally changed the semantics of the thresholds used to select between f and e formatting for the default floating-point representation.

P3505R3 specified the thresholds as the representable values nearest to the mathematical boundaries:

The conversion specifier is f if the absolute value of value is in the range [m, n), where m is the nearest representable as T value of 10-4 and n is the nearest representable as T value of std::numeric_limits<T>::radixstd::numeric_limits<T>::digits + 1 rounded down to the nearest power of 10, e otherwise

However, P3505R4, approved in Brno, changed this to:

The conversion specifier is f if the absolute value of value is in the range [l, u), where l is the smallest value larger or equal to 10-4 that is representable by T and u is the largest value smaller or equal to std::numeric_limits<T>::radixstd::numeric_limits<T>::digits + 1 rounded down to the nearest power of 10 representable by T, otherwise e.

This changes observable behavior. For example, on IEEE-754 implementations, the nearest representable float value to 10-4 is slightly smaller than 10-4. Under the wording in P3505R3 it is formatted using f, while under the wording in P3505R4 it is formatted using e.

For example:

std::format("{}", 0.0001f);

produces "0.0001" under the original wording, but "1e-4" under the current wording.

This change was unintended. The wording should be restored to match the original design approved by LEWG.

The upper bound is unaffected but reverting the wording changes there as well improves consistency.

Proposed resolution:

This wording is relative to N5046 plus the wording changes applied by P3505R4 (isocpp.org/P3505R4) approved at the 2026 Brno meeting.

  1. Modify 28.2.2 [charconv.to.chars] as indicated:

    to_chars_result to_chars(char* first, char* last, floating-point-type value);
    

    -7- Effects: Let T be floating-point-type. value is converted to a string in the style of printf in the "C" locale.

    The conversion specifier is f if the absolute value of value is in the range [l, u), where l is the smallest value larger or equal to 10-4 that is representable by Tnearest representable as T value of 10-4 and u is the largest value smaller or equal to std::numeric_limits<T>::radixstd::numeric_limits<T>::digits + 1 rounded down to the nearest power of 10 representable by Tnearest representable as T value of std::numeric_limits<T>::radixstd::numeric_limits<T>::digits + 1 rounded down to the nearest power of 10, otherwise e.

    -8- Throws: Nothing.