-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
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:
Line 2278 in 926d458
| _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:
Line 2297 in 926d458
| _Width += _Zeroes_to_append; |
Later, we use _Zeroes_to_append in a clamped manner (i.e. negative values are treated as zero):
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:
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; | |
| } | |
| } | |
| } |