Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

best way to output a full precision double into a text file

I need to use an existing text file to store some very precise values. When read back in, the numbers essentially need to be exactly equivalent to the ones that were originally written. Now, a normal person would use a binary file... for a number of reasons, that's not possible in this case.

So... do any of you have a good way of encoding a double as a string of characters (aside from increasing the precision). My first thought was to cast the double to a char[] and write out the chars. I don't think that's going to work because some of the characters are not visible, produce sounds, and even terminate strings ('\0'... I'm talkin to you!)

Thoughts?

[Edit] - once I figure out which of the solutions proposed works best for me, I'll mark one as 'the' solution.

like image 642
fbl Avatar asked Jan 10 '11 04:01

fbl


People also ask

How do I print a double with full precision in C++?

How do I print a double value with full precision using cout in C++? The output stream cout allows using manipulators that you can use to set the precision directly on cout and use the fixed format specifier. To get the full precision of a double, you can use the limits library.

How to get the precision of a double in Cout?

The output stream cout allows using manipulators that you can use to set the precision directly on cout and use the fixed format specifier. To get the full precision of a double, you can use the limits library. For example,

How to set precision for double values in Java?

How to set Precision for Double values in Java? Given a double value val, the task is to set its precision value to a specific decimal places. We can use String.format () method to format the decimal number to some specific format.

How to set the precision of a float or double?

You can set the precision directly on std::cout and use the std::fixed format specifier. You can #include <limits> to get the maximum precision of a float or double. Show activity on this post. Show activity on this post. Here is what I would use:


6 Answers

If you want to keep the format strictly human readable, you can write out the double thusly:

#include <iomanip>
#include <sstream>

std::string doubleToText(const double & d)
{
    std::stringstream ss;
    //ss << std::setprecision( std::numeric_limits<double>::digits10+2);
    ss << std::setprecision( std::numeric_limits<int>::max() );
    ss << d;
    return ss.str();
}

std::numeric_limits<int>::max() will output with the maximum possible decimal precision. This will preserve the value most precisely across differently floating point implementations. Swapping that line for the commented line using std::numeric_limits<double>::digits10+2 will give just enough precision to make the double precisely recoverable on the platform the code is compiled for. This gives a much shorter output and preserves as much information as the double can uniquely represent.

The C++ stream operators do not preserve denormalized numbers or the infinities and not-a-numbers when reading strings in. However, the POSIX strtod function does, and is defined to by the standard. Hence, the most precise way to read a decimal number back with a standard library call would be this function:

#include <stdlib.h>

double textToDouble(const std::string & str)
{
    return strtod( str.c_str(), NULL );
}
like image 66
fuzzyTew Avatar answered Sep 26 '22 02:09

fuzzyTew


Assuming IEEE 754 double, printf("%.17g\n", x) will give you enough digits to recreate the original value.

like image 35
dan04 Avatar answered Sep 27 '22 02:09

dan04


A two step process: First use binary float/double serialization and then apply base 64 encoding. The result is not human readable, but will not loose precision.

Edit: (Thanks to fuzzyTew and dan04)

Lossless decimal and human readable representation is probably possible, but would require much more space.

like image 42
Juraj Blaho Avatar answered Sep 29 '22 02:09

Juraj Blaho


You could use base 64. This would allow you to store the exact byte values in a text file.

I haven't used it, but I found this base 64 encoding/decoding library for C++.

like image 21
Daniel Gallagher Avatar answered Sep 29 '22 02:09

Daniel Gallagher


To print long lists of numbers in C++ without loss (write and read in the same arquitecture) I use this (for doubles):

#include<iostream>
#include<iomanip>
#include<limits>
#include<cmath>

#include<sstream>
int main(){
std::ostringstream oss;

int prec = std::numeric_limits<double>::digits10+2; // generally 17

int exponent_digits = std::log10(std::numeric_limits<double>::max_exponent10)+1; // generally 3
int exponent_sign   = 1; // 1.e-123
int exponent_symbol = 1; // 'e' 'E'
int digits_sign = 1;
int digits_dot = 1; // 1.2

int division_extra_space = 1;
int width = prec + exponent_digits + digits_sign + exponent_sign + digits_dot + exponent_symbol + division_extra_space;

double original = -0.000013213213e-100/33215.;
oss << std::setprecision(prec) << std::setw(width) << original << std::setw(width) << original << std::setw(width) << original << '\n';
oss << std::setprecision(prec) << std::setw(width) << 1. << std::setw(width) << 2. << std::setw(width) << -3. << '\n';
}

prints

 -3.9780861056751466e-110 -3.9780861056751466e-110 -3.9780861056751466e-110
                        1                        2                       -3

In summary, in my case it is like setting:

oss << std::precision(17) << std::setw(25) << original << ...;

In any case I can test if this works, by doing:

    std::istringstream iss(oss.str());
    double test; iss >> test;
    assert(test == original);
like image 37
alfC Avatar answered Sep 25 '22 02:09

alfC


I was sure there was a special format specifier for printf (maybe %a?) that allowed printing the binary representation of a float, but I cannot find it..
However, you can try this:

int main(int argc, char* argv[]){
    union fi {
        unsigned int i;
        float        f;
    } num;
    num.f = 1.23f;
    printf("%X\n", num.i);
    return 0;
}
like image 1
ruslik Avatar answered Sep 25 '22 02:09

ruslik