There is wonderful work of Florian Loitsch called "Printing Floating-Point Numbers Quickly and Accurately with Integers". This sounds pretty useful in case of printing any kind of double into string. I think many people included me until recently only know like setting a fix precision with setprecisiton(n)
or printf("%0.nf")
and often either choosing n
too large and getting floating point imprecision or too small and cutting off valuable data. I wonder is there something similar to this in C++ standard (including upcoming), boost, libc, or somewhere easily reachable and tested?

- 28,148
- 6
- 56
- 87

- 3,857
- 5
- 25
- 43
-
Before reading the PDF: `printf("%g", value)`? – pmg Mar 26 '21 at 18:08
-
Uses default precision 6, i.e. again you have to specify precision. – Yuki Mar 26 '21 at 18:11
-
Does this answer your question? [How do I print a double value with full precision using cout?](https://stackoverflow.com/questions/554063/how-do-i-print-a-double-value-with-full-precision-using-cout) – Woodford Mar 26 '21 at 18:13
-
2C and C++ are different languages and while yield different answers. I've removed the C tag, since the question specifically mentions the C++ standard and thus seems to be targeting C++. – François Andrieux Mar 26 '21 at 18:13
-
As the paper says, “ Correct printing become part of the specification of many languages and furthermore all major C libraries (and as a consequence all programs relying on the `printf` functions) adapted accurate algorithms and print correct results now.” – Pete Becker Mar 26 '21 at 18:17
-
Do you specifically want the algorithm in that paper that prints with the fewest digits necessary to identify the original value, or are the algorithms that produce a fixed number of digits (selected to be always sufficient) acceptable? – Eric Postpischil Mar 26 '21 at 18:17
-
@EricPostpischil, any algorithm that produces nearest decimal number is fine. – Yuki Mar 26 '21 at 18:47
-
@Yuki How accurate do you want that _decimal number_? With zero error? – chux - Reinstate Monica Mar 26 '21 at 18:57
-
Yuki, concerning "choosing n too large and getting floating point imprecision or too small ..." You may find [Printf width specifier to maintain precision of floating-point value](https://stackoverflow.com/q/16839658/2410359) useful. – chux - Reinstate Monica Mar 26 '21 at 19:00
-
fyi read some of these posts on round-tripping float and double - https://www.exploringbinary.com/tag/floating-point/ – Richard Critten Mar 26 '21 at 19:32
2 Answers
I don't think there is any really good solution in the standard C++ library.
I use the trick of trying several different formats, and then selecting the text representation that is the shortest and the text representation has the exact same value when round-tripped. Which I use to save in my text file (XML) output.
Which sometimes means selecting the exacting hexadecimal floating point representation. (May be a deal breaker for your use case.)
Here's the code, which I've added a table to generate some examples, and mark them as *
if they are the shortest, or with a warning marker if they do not round trip.
#include <iomanip>
#include <ios>
#include <iostream>
#include <sstream>
using std::cout;
using std::defaultfloat;
using std::fixed;
using std::hexfloat;
using std::istringstream;
using std::left;
using std::scientific;
using std::setw;
using std::string;
using std::stringstream;
enum class cap { title, middle, end };
static void print(const char* text, double num, cap c) {
stringstream ss;
ss << fixed << num;
auto s = ss.str();
double fn = stod(s);
size_t flen = s.length();
string falert = "";
if (fn != num) { falert = "/!\\"; flen += 100; }
ss.str("");
ss.clear();
ss << scientific << num;
s = ss.str();
double sn = stod(s);
size_t slen = s.length();
string salert = "";
if (sn != num) { salert = "/!\\"; slen += 100; }
ss.str("");
ss.clear();
ss << hexfloat << num;
s = ss.str();
double hn = stod(s);
size_t hlen = s.length();
string halert = "";
if (hn != num) { halert = "/!\\"; hlen += 100; }
ss.str("");
ss.clear();
ss << defaultfloat << num;
s = ss.str();
double dn = stod(s);
size_t dlen = s.length();
string dalert = "";
if (dn != num) { dalert = "/!\\"; dlen += 100; }
char gbuf[256];
sprintf(gbuf, "%g", num);
s = gbuf;
double gn = stod(s);
size_t glen = s.length();
string galert = "";
if (gn != num) { galert = "/!\\"; glen += 100; }
if (flen <= slen && flen <= hlen && flen <= dlen) falert += "*";
if (slen <= flen && slen <= hlen && slen <= dlen) salert += "*";
if (hlen <= flen && hlen <= slen && hlen <= dlen) halert += "*";
if (dlen <= flen && dlen <= hlen && dlen <= slen) dalert += "*";
if (glen <= dlen && glen <= flen && glen <= hlen && glen <= slen) galert += "*";
if (c == cap::title) cout <<
"┌──────────┬────────────┬──────────────────────────┐\n"
"│ number │ iomanip │ representation │\n"
"├──────────┼────────────┼──────────────────────────┤\n"
;
cout << left
<< "│ " << setw(8) << text << " │ fixed │ " << setw(24) << fixed << num << " │" << falert << "\n"
<< "│ " << setw(8) << text << " │ scientific │ " << setw(24) << scientific << num << " │" << salert << "\n"
<< "│ " << setw(8) << text << " │ hexfloat │ " << setw(24) << hexfloat << num << " │" << halert << "\n"
<< "│ " << setw(8) << text << " │ default │ " << setw(24) << defaultfloat << num << " │" << dalert << "\n"
<< "│ " << setw(8) << text << " │ %g │ " << setw(24) << gbuf << " │" << galert << "\n"
;
cout << (c != cap::end ?
"├──────────┼────────────┼──────────────────────────┤\n" :
"└──────────┴────────────┴──────────────────────────┘\n" );
}
static void table() {
print("0.0", 0.0, cap::title);
print("0.01", 0.01, cap::middle);
print("0.00001", 0.00001, cap::middle);
print("1e99" , 1.e+99, cap::middle);
print("0.1" , 0.1, cap::middle);
print("0.2" , 0.2, cap::middle);
print("0.3" , 0.3, cap::middle);
print("0.4" , 0.4, cap::middle);
print("0.5" , 0.5, cap::middle);
print("0.6" , 0.6, cap::middle);
print("0.7" , 0.7, cap::middle);
print("0.8" , 0.8, cap::middle);
print("0.9" , 0.9, cap::middle);
print("NTSC" , 30.0/1001.0, cap::middle);
print("1/3" , 1.0/3.0, cap::end);
}
int main() {
table();
}

- 4,648
- 3
- 16
- 27
Commonly available functions for accurate floating-point number printing
Post originally tagged [C] and [C++]
// Hexadecimal/decimal exponential output.
printf("%a\n", value);
// Decimal exponential output with sufficient precision to distinguish against other double
printf("%.*e\n", DBL_DECIMAL_DIG - 1, double_value);
// Decimal sometimes exponential output with sufficient precision to distinguish against other double
printf("%.*g\n", DBL_DECIMAL_DIG, double_value);
All finite floating point values are exact. Rarely does one need to see it exactly as a decimal. That takes more code.

- 143,097
- 13
- 135
- 256
-
OP may want the algorithm that produces the fewest number of digits required to uniquely identify the original value for the specific number being converted. The C++ library routines do not do this, even if they round correctly (which the standard does not require, unless it has been upgraded). – Eric Postpischil Mar 26 '21 at 18:18
-
@EricPostpischil With language tag edit by non-OP, this C answer may still shed some light for OP. As to what OP truly wants, if it is not "Commonly available functions for accurate floating-point number printing" of the title, may also evolve. – chux - Reinstate Monica Mar 26 '21 at 18:24
-
@chux Thank you. But that would not work, it does not represent numbers, accurately. For example, `100.74` would be represented incorrectly in single precision using this approach. – Yuki Mar 26 '21 at 18:39
-
@Yuki Surely that's a question of *internal representation*. Most decimal fractions can only be *approximated* by binary fractions, which is what finite-precision IEEE-754 binary floating-point numbers are. This seems to be a duplicate of "Is floating point math broken?" – njuffa Mar 26 '21 at 18:45
-
@njuffa I do not think the math is broken. I know some fundamental of how floating-point works internally. You can try to read the begging of the paper to get the flavor of what I am talking about. – Yuki Mar 26 '21 at 18:49
-
@Yuki Question is about " floating-point number". `100.74` is not exactly representable as a `float` nor `double`. It is not a FP value. `printf("%a\n", value);` reports FP values exactly and accurately with 0 error. Are you asking about FP values or code like `100.74`? – chux - Reinstate Monica Mar 26 '21 at 18:55
-
@Yuki I *am* familiar with the paper. See this [answer](https://stackoverflow.com/a/7159280/780717) – njuffa Mar 26 '21 at 19:03