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.
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.
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? 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.
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:
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 );
}
Assuming IEEE 754 double, printf("%.17g\n", x)
will give you enough digits to recreate the original value.
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.
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++.
To print long lists of numbers in C++ without loss (write and read in the same arquitecture) I use this (for double
s):
#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);
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With