Namespaces
Variants
Views
Actions

Talk:cpp/string/basic string/to string

From cppreference.com

Not round-trip safe.

Please mention that std::to_string is not round-trip-safe for floating point numbers. Please mention "not round-trip-safe" explaining that converting a double to a std::string and then back to a double will not yield the same number in every case.

Please provide an example of how to perform a round-trip-safe conversion, e.g. maybe something similar to this:

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <limits>
#include <sstream>
#include <cassert>
 
void print(const char *msg, double numBefore, const std::string &sNum, bool maybeLucky = false)
{
    double numAfter;
    std::istringstream(sNum) >> numAfter;
    std::cout << msg << sNum;
    if (numBefore == numAfter) {
        std::cout << " \t(round-trip-safe!";
        if (maybeLucky) {
            std::cout << " - lucky here: too simple number";
        }
        std::cout << ')';
    }
    std::cout << '\n';
}
 
void run(const double x)
{
    const auto maxDig10 = std::numeric_limits<decltype(x)>::max_digits10;
    std::ostringstream oss;
    oss << std::setprecision(maxDig10) << x;
    const std::string sNum    = oss.str();
 
    oss.str(""); oss.clear();
    oss << std::setprecision(maxDig10-1) << std::scientific << x;
    const std::string sNumFixed = oss.str();
 
    char sNumAlt[1000]; // must be large enough (todo: what is just-just large enough??)
    std::snprintf(sNumAlt, sizeof(sNumAlt), "%.*g", maxDig10, x);
 
    const std::string sNumBad = std::to_string(x);
 
    print("ostringstream                      -> ", x, sNum);
    print("ostringstream with std::scientific -> ", x, sNumFixed);
    print("snprintf                           -> ", x, sNumAlt);
    print("std::to_string()                   -> ", x, sNumBad, true);
}
 
int main()
{
    for (double x : {3.3333333333333333333, 0.00033333333333333333333333, 1., 1000000000000000000000., std::numeric_limits<double>::lowest()}) {
        run(x);
        std::cout << '\n';
    }
}

(By the way: how could something so ugly (std::to_string not doing the normal good sane thing), get into the standard??)

The notes allude to this and the example makes it obvious. That said, it is changing behaviour in C++26 to print the same way std::to_chars does (i.e. shortest representation that preserves round trip) --Ybab321 (talk) 11:49, 26 July 2023 (PDT)