Reputation:
Is there any combination of stream manipulators (or any other method in the standard C++) that would allow me to get the "right" number of digits when printing double
in C++?
By the "right" number I mean the number of digits as defined here:
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
In a bit of a simplistic example, let's suppose that we have three double
values: DD, D0 and D1. DD is the "middle", D1 has mantissa larger by 1, D0 smaller by 1.
When printed to some very large arbitrary precision, they produce the following values (the numbers in the example are completely off the wall):
D0 => 1.299999999701323987
DD => 1.300000000124034353
D1 => 1.300000000524034353
(EPSILON, the value of least significant bit of mantissa at 0 exponent, is ~ 0.0000000004)
In that case, the method above would produce
D0 => 1.2999999997
DD => 1.3
DD => 1.3000000005
Upvotes: 6
Views: 401
Reputation: 96906
If I understand you correctly, you want std::to_chars
.
value is converted to a string as if by
std::printf
in the default ("C") locale. The conversion specifier isf
ore
(resolving in favor off
in case of a tie), chosen according to the requirement for a shortest representation: the string representation consists of the smallest number of characters such that there is at least one digit before the radix point (if present) and parsing the representation using the correspondingstd::from_char
s function recovers value exactly. If there are several such representations, one with the smallest difference to value is chosen, resolving any remaining ties using rounding according tostd::round_to_nearest
.
It's a low-level function, so printing the result requires some work:
#include <charconv>
#include <iostream>
int main()
{
double val = 0.1234;
char buf[64];
*std::to_chars(buf, buf + sizeof buf, val).ptr = '\0';
std::cout << buf << '\n';
}
This function needs an up-to-date standard library: GCC (libstdc++) 11 or newer, or Clang (libc++) 14 or newer (currently trunk). MSVC also supports it.
Upvotes: 5
Reputation: 40043
Absent the C++17 library function that isn’t implemented everywhere yet, you can just try precisions (with whatever equivalent of %g
) until one rounds back exactly. If you don’t care about subnormal numbers (where even two digits can be too many), start at 15 for IEEE 754 doubles; that never produces meaningless trailing digits. You’ll never need to go past 17.
Upvotes: -1