https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120967

            Bug ID: 120967
           Summary: std::format produces incorrect results when printing
                    large floating point numbers when using the alternate
                    flag and precision set to 0
           Product: gcc
           Version: 14.3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dominick.allen1989 at gmail dot com
  Target Milestone: ---

Created attachment 61806
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61806&action=edit
Bug reproducing input file

When printing using format specifications, be it std::print or std::format, the
use of the alternate flag with a precision of 0 produces incorrect results
where the decimal point is off by one, and a leading null terminating byte is
present. The transition point for a suitably large number happens to be
`std::numeric_limits<double>::max() / exp2(512 + 64 + 16 + 8 + 2)`, where after
that point the correct behavior is present. This is only the case for
libstdc++; clang only reproduces this behavior if it is not configured to use
libc++, in which case it produces correct results.

```
#include <cmath>
#include <limits>
#include <format>
#include <cstdio>
#include <print>
#include <iostream>

void demoBug(double value) {
    std::print("Printing {:e} with std::print and std::format\n", value);
    std::print("With std::print\n{0:#.0f}\n{0:f}\n", value);

    std::print("With std::format\n");
    auto output1 = std::format("{:#.0f}\n", value);
    auto output2 = std::format("{:f}\n", value);
    std::cout << output1;
    std::cout << std::format("{:f}\n", value);

    std::print("The first byte of output1 is {:#X}\n", output1[0]);
    std::print("The first byte of output2 is {:#X}\n", output2[0]);
}

int main() {
    demoBug(std::numeric_limits<double>::max());

    std::print("Printing {:e} printf\n", std::numeric_limits<double>::max());
    printf("%#010.0f\n%f\n", std::numeric_limits<double>::max(),
           std::numeric_limits<double>::max());

    demoBug(std::numeric_limits<double>::max() /
            exp2(512 + 64 + 16 + 8 + 2));
    demoBug(std::numeric_limits<double>::max() /
            exp2(512 + 64 + 16 + 8 + 2 + 1));

    return 0;
}
```

Output:
```
libfud@localhost ~/Documents/bug_reports/format $ g++ -std=c++23 main.cpp -o
format_float_fixed && ./format_float_fixed
Printing 1.797693e+308 with std::print and std::format
With std::print
17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407586850845513394230458323690322294816580855933212334827479782620414472316873817718091929988125040402618412485836.8
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000
With std::format
17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407586850845513394230458323690322294816580855933212334827479782620414472316873817718091929988125040402618412485836.8
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000
The first byte of output1 is 0X0
The first byte of output2 is 0X31
Printing 1.797693e+308 printf
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000
Printing 1.083074e+127 with std::print and std::format
With std::print
1083074099265943184277437802660630803713451676954622548041022082071609068148274766550887916516477217352904724481640675010622259.2
10830740992659431842774378026606308037134516769546225480410220820716090681482747665508879165164772173529047244816406750106222592.000000
With std::format
1083074099265943184277437802660630803713451676954622548041022082071609068148274766550887916516477217352904724481640675010622259.2
10830740992659431842774378026606308037134516769546225480410220820716090681482747665508879165164772173529047244816406750106222592.000000
The first byte of output1 is 0X0
The first byte of output2 is 0X31
Printing 5.415370e+126 with std::print and std::format
With std::print
5415370496329715921387189013303154018567258384773112740205110410358045340741373832754439582582386086764523622408203375053111296.
5415370496329715921387189013303154018567258384773112740205110410358045340741373832754439582582386086764523622408203375053111296.000000
With std::format
5415370496329715921387189013303154018567258384773112740205110410358045340741373832754439582582386086764523622408203375053111296.
5415370496329715921387189013303154018567258384773112740205110410358045340741373832754439582582386086764523622408203375053111296.000000
The first byte of output1 is 0X35
The first byte of output2 is 0X35
```

https://godbolt.org/z/qdvc34KrW

Output of `g++ -v`:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/14/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-pc-linux-gnu
Configured with:
/var/tmp/portage/sys-devel/gcc-14.3.0/work/gcc-14.3.0/configure
--host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --prefix=/usr
--bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/14
--includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/14/include
--datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/14
--mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/14/man
--infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/14/info
--with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/14/include/g++-v14
--disable-silent-rules --disable-dependency-tracking
--with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/14/python
--enable-languages=c,c++,fortran --enable-obsolete --enable-secureplt
--disable-werror --with-system-zlib --enable-nls --without-included-gettext
--disable-libunwind-exceptions --enable-checking=release
--with-bugurl=https://bugs.gentoo.org/ --with-pkgversion='Gentoo 14.3.0 p8'
--with-gcc-major-version-only --enable-libstdcxx-time --enable-lto
--disable-libstdcxx-pch --enable-shared --enable-threads=posix
--enable-__cxa_atexit --enable-clocale=gnu --enable-multilib
--with-multilib-list=m32,m64 --disable-fixed-point --enable-targets=all
--enable-offload-defaulted --enable-offload-targets=nvptx-none --enable-libgomp
--disable-libssp --disable-libada --enable-cet --disable-systemtap
--disable-valgrind-annotations --disable-vtable-verify --disable-libvtv
--with-zstd --without-isl --enable-default-pie --enable-host-pie
--enable-host-bind-now --enable-default-ssp --disable-fixincludes
--with-gxx-libcxx-include-dir=/usr/include/c++/v1
--with-build-config=bootstrap-cet
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 14.3.0 (Gentoo 14.3.0 p8)

Reply via email to