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:
Run this code
#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)
- The size of
char sNumAlt[X];"just-just large enough" buffer could be estimated like this:
Run this code
#include <limits>
#include <iostream>
int main()
{
using your_numeric_type_t = long double; // or any other of arithmetic types
constexpr std::size_t X
= std::numeric_limits<your_numeric_type_t>::max_exponent10
+ std::numeric_limits<your_numeric_type_t>::max_exponent10 / 3 + 1
// for possible locale dependent thousands separators
+ 3 // for sign, null-terminator, digital dot
+ 6 // trailing 6 digits of "fixed" format
+ 1 // rounding and safety.)
;
std::cout << X << '\n';
}
Possible output:
6587
--Space Mission (talk) 15:59, 26 July 2023 (PDT)