1

In the following code:

using seconds = std::chrono::duration<long double, std::ratio<1, 1>>;
using namespace std::literals;

int main() {
    seconds s = 10ms + 10us + 10ns;
    std::print("from chrono {} | from count {:%Q}\n", s, s);
}

I get the print out:

from chrono 0.01001s | from count 0.01001001

See live example.

Why is the format for chrono passed directly in cropping the time this way? The chrono duration can represent the nanoseconds and clearly the format specification allows printing decimals. Why does it stop after 5 decimal places?

If i change it to:

 seconds s = 10ms + 10us + 123ns;
 std::print("from chrono {} | from count {:%Q}\n", s, s);

See live example

Then i get

from chrono 0.0100101s | from count 0.010010123

Which has more precision but is still wrong. There does not appear to be a format specifier that affects this (format specialisation).

What is the explanation for this behaviour?

5
  • 2
    It stops at six significant digits and doesn't output trailing zeros, i.e. it is the normal floating point output. You can specify the precision in the format. Commented Jan 29 at 7:14
  • @molbdnilo Why does it choose 32bit floating point output though? It knows the type of the duration is double? If i print a double the same way (aka count) it gives me the correct precision. Commented Jan 29 at 22:05
  • @molbdnilo, in fact even if i print a double and float containing that number it still prints the right thing. Where does it specify that it stops at 6 significant digits? Commented Jan 29 at 22:07
  • @molbdnilo precision specifiers seem to be ignored for durations godbolt.org/z/jd3vhr9PG Commented Jan 30 at 12:29
  • precision specifiers do work with fmtlib godbolt.org/z/xYjfvoMva (though clang doesn't seem to be able to compile the duration prints?) Commented Jan 30 at 12:48

1 Answer 1

-2

This behavior is due to how the formatting and output functions work with std::chrono durations, particularly when used with floating-point durations like long double. The seconds type is defined as a std::chrono::duration<long double, std::ratio<1, 1>>. long double is a floating-point type, and floating-point numbers can only represent values with a certain precision. Even though you expect a high degree of precision (e.g., nanoseconds), the actual precision can be constrained by the internal representation of the floating-point type. The default behavior of std::chrono::duration when formatted in this way is that it rounds the printed value to a reasonable precision and does not output the trailing zeros. This is done for simplicity, to avoid excessively long outputs for values that don't need that much precision for most applications.

Some suggestions which you can try out:

  • Use std::setprecision to control the output precision

    Example:

    seconds s = 10ms + 10us + 10ns;
    std::cout << "from chrono " << std::fixed << std::setprecision(9) << s.count() << "s\n";  // Manually set precision
    
  • if your goal is to display the duration in a smaller time unit (e.g., nanoseconds) for greater precision, you can use std::chrono::duration_cast to convert the duration to a finer-grained unit, like nanoseconds.

    Example:

    auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(s);
    std::cout << "from chrono " << nanos.count() << "ns\n";
    
Sign up to request clarification or add additional context in comments.

4 Comments

The answer smells a machine text. Very big and generic introduction is quite vague.
...and it doesn't really answer the question. The OP already uses .count() to get more precision, they're asking how to get more precision when printing the duration directly
I guess when %Q is used, we can not set the precision explicitly. Also when I was working with chrono library, I have used duration cast to convert from seconds to milliseconds so I thought this might help to get actual value.
yeah, sorry, i am not really happy with this answer. I am not looking for a work around, i want to understand how the format specialization for chrono works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.