Thanks to visit codestin.com
Credit goes to github.com

Skip to content

<format>: Alternate form general floating-point can mishandle width #5011

@StephanTLavavej

Description

@StephanTLavavej

Reported to me by Attila Feher. https://godbolt.org/z/djh5KxjW6

#include <format>
#include <iostream>
using namespace std;

int main() {
    std::cout << "Expected: [1.e-37]\n";
    std::cout << format("  Actual: [{:#6.0g}]\n", 1.234e-37);
}

libstdc++ and libc++ behave as expected, but MSVC prints:

Expected: [1.e-37]
  Actual: [ 1.e-37]

🕵️ Analysis

I debugged into this, and although I'm not absolutely certain of the root cause yet, this line appears to be involved:

_Zeroes_to_append = _Extra_precision + _Precision - _Digits;

_Zeroes_to_append is computed as -1 because _Extra_precision and _Precision are both 0, and _Digits is 1.

We've correctly computed _Width to be 6, but the negative _Zeroes_to_append damages it, which appears to be the proximate cause of the bug:

_Width += _Zeroes_to_append;

Later, we use _Zeroes_to_append in a clamped manner (i.e. negative values are treated as zero):

STL/stl/inc/format

Lines 2328 to 2330 in 926d458

for (; _Zeroes_to_append > 0; --_Zeroes_to_append) {
*_Out++ = '0';
}

However, we need to completely understand the problem and all possible codepaths before developing a fix (i.e. we can't just clamp it to zero and call it a day). Note that the chars_format::general codepath further adjusts _Zeroes_to_append:

STL/stl/inc/format

Lines 2278 to 2289 in 926d458

_Zeroes_to_append = _Extra_precision + _Precision - _Digits;
// Leading zeroes are not significant if we used fixed point notation.
if (_Exponent_start == _Result.ptr && _STD abs(_Value) < 1.0 && _Value != 0.0) {
for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) {
if (*_It == '0') {
++_Zeroes_to_append;
} else if (*_It != '.') {
break;
}
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!formatC++20/23 format

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions