user3458
user3458

Reputation:

Java-style printing of `double` in C++

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

Answers (2)

HolyBlackCat
HolyBlackCat

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 is f or e (resolving in favor of f 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 corresponding std::from_chars 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 to std::round_to_nearest.

It's a low-level function, so printing the result requires some work:

run on gcc.godbolt.org

#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

Davis Herring
Davis Herring

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

Related Questions