Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print double with all decimals in Qt?

First of all this is no duplicate. I searched the web but no answer is sufficient.

I want to print a double. So I have to convert it to a QString. I want to have no scientific notation and 0.1 should print 0.1 and 1/3 should print as much 0.33333... as double is capable to represent. Unfortunately I can find only solutions with fixed precision, which leads to eiter a capped 0.333333 (end after specified p loosing precision) or an unnecessary zero filled 0.100000.

I know I could max out the precision and drop all trailing zeroes, but isnt there a nice solution, which just prints max possible but min necessary precision?

Edit: I guess I need to clearify a few things. This question is not about to map the space of real numbers into single, double or whatever precision floating point numbers. It is about the inverse: the mapping of the 64 bit double precision floating point space into our beloved realworld real numbers. Since the former is a subset of the latter there is, in theory, absolutely no problem doing this.

like image 541
ManuelSchneid3r Avatar asked Mar 05 '16 11:03

ManuelSchneid3r


2 Answers

Try simplest thing QString::number(1.0/3.0, 'g', 17); or when using std::ostream there is std::setprecision used to control number of decimals for operator<<

like image 195
Radek Avatar answered Sep 29 '22 07:09

Radek


The Problem

Contrary to the other comments and answers here, this is a very reasonable request, and the question seems pretty clear. Floating-point conversion to strings should usually have the properties described in the question, instead of the primitive form found in the C and C++ standard libraries. You should not need to specify the precision, as the algorithm should use what is necessary. To expand a bit, say you pick a fixed precision of 6. Then you print three 64-bit floats without scientific notation, (the ones closest to) 0.1, 1.0/3.0, and 1.0/3000.0:

0.100000
0.333333
0.003333

There are a couple problems here. With 0.1, there are unnecessary zeros printed at the end. It is much cleaner and just as accurate to print 0.1. With the other numbers, the value has been truncated. A 64-bit float can represent 15+ decimal digits, but we just printed 6. If you convert the string back to a float, you won't get the same value. So let's choose a precision of 17:

0.10000000000000001
0.33333333333333331
0.00333333333333333

Now we are representing the value of 1.0/3.0 better, but 0.1 only looks worse. It would be just as accurate and look much better to print 0.1. Also, we are still truncating 1.0/3000.0. There is no fixed precision you can pick to make numbers print nicely.

The Solution

There is an old and somewhat slow algorithm (Dragon) to solve this problem:

http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf

And there is a much faster algorithm, Grisu, published in 2010, but it needs to fall back to an algorithm such as Dragon for 0.5% of floating-point numbers:

http://dl.acm.org/citation.cfm?doid=1809028.1806623

Several language implementations have adopted Grisu for printing floating-point numbers (such as Firefox's and Chrome's JS engines and Rust's standard library). There's also an algorithm just published in 2016, Errol, that improves upon Grisu and doesn't need to fall back to Dragon. It is so new it probably hasn't seen any adoption yet:

http://dl.acm.org/citation.cfm?id=2837654

I needed good floating-point printing today, so I've been experimenting with Qt, and it doesn't seem that Qt can do what the question asks for. QString::number and QString::arg both use a poor algorithm.

In the Qt 5.7 new features list, there is this note:

Added the ability to convert a floating point to its shortest, exact string form, without having to pre-calculate how many digits that is; QVariant uses this

In my tests, using QVariant{floatValue}.toString() seems to meet the requirements, except for still using scientific notation with very small and large numbers. Here is a C++ library by the inventor of the Grisu algorithm that looks excellent (and it allows choosing when it uses scientific notation):

https://github.com/google/double-conversion

like image 26
Jordan Miner Avatar answered Sep 29 '22 06:09

Jordan Miner