Convert float to string without losing precision
I want to store a float value into string without lossing or adding any single precision digits.
For example if my float value is 23.345466467 , I want my string to have str = "23.345466467" exact digits.
I tried using CString format function with %f. Its giving only first 6 precision. or if i use %10 , if my float value is having less than 10 precision,its adding some more junk precis开发者_如何学Goion. I want to get exact float value into my string. how to do this?
See the nice detailed discussion in http://randomascii.wordpress.com/2012/03/08/float-precisionfrom-zero-to-100-digits-2/ .
The short answer is that the minimum precision is the following:
printf("%1.8e", d); // Round-trippable float, always with an exponent
printf("%.9g", d); // Round-trippable float, shortest possible
printf("%1.16e", d); // Round-trippable double, always with an exponent
printf("%.17g", d); // Round-trippable double, shortest possible
Or equivalently, with a std::ostream& os
:
os << scientific << setprecision(8) << d; // float; always with an exponent
os << defaultfloat << setprecision(9) << d; // float; shortest possible
os << scientific << setprecision(16) << d; // double; always with an exponent
os << defaultfloat << setprecision(17) << d; // double; shortest possible
That would depend upon whether your float value 23.345466467 is exactly representable (likely not)
What Every Computer Scientist Should Know About Floating-Point Arithmetic
Why Floating-Point Numbers May Lose Precision
I would also question why you need to do this? What are you going to use the string representation for? Are you aware of the double and decimal types?
[Untested: you could try casting to double and then using "%d" Maybe this will pull in the extra 'guard' digits' but it still won't work for all values]
C99 supports the %a
format in printf
that allows to output the contents of a double without loss of precision.
Others have already commented that 23.345466467 does not exist as a float, but if your goal is just round-trip conversion of float values that do exist without accidentally changing their value slightly, you can either use snprintf
and strtod
with at least DECIMAL_DIG
places (POSIX, but not plain ISO C, guarantees this round-trip to be exact) or print the float in hex instead of decimal. C99 has the %a
format specifier for printing floats in hex, but if you can't depend on C99, it's easy to write your own. Unlike with decimal, the naive algorithm for printing hex floats works just fine. It goes like:
- Scale by a power of 2 to put the value in the range
0x8 <= val < 0x10
. This power of 2 becomes the exponent in your result. - Repeatedly remove the integer portion of
val
and multiply by0x10
to get the output digits. - When
val
reaches 0, you're done.
Conversion in the opposite direction is likewise easy.
The number of (decimal) digits you need to uniquely represent any float
is by definition std::numeric_limits<float>::maxdigits10
. The float
format cannot distinguish between 0.0
and 0.0000
so this constant is the maximum value you'll ever need.
Now, note that I said uniquely. This is not exact. It means that if you write two different binary values, you'll get two different decimal representations. It also means that if you read back such a decimal representation, it cannot be confused with any other value, and therefore you get back the precise same binary value you had before. Usually, those two guarantees are sufficient.
[edit]
std::numeric_limits<float>::digits10
represents the reverse concept: the largest number of decimal digits such that decimal->binary->decimal is guaranteed exact.
Maybe you case use fprintf() (from ) to convert your float into a string. But the precision might be lost immediately after the affectation because 'flaot' and 'double' have a limited precision. Someone must confirm that.
The best way is to store its binary representation, as suggested by @pgm. However, you could also store it in decimal notation, but with use of period notation, like :
23.5095446(1545855463)
In this way they could be stored somehow "lossless", but it will require very careful coding.
Are you storing it so that you can re-read it later and use it as a float? Or do you care what the string says? As others have said you need to write the binary representation rather than the base10. Or you can be a little tricky and do something like this
float f=23.345466467
int i=*(int*)&f; //re-interpret the bits in f as an int
cout << i;
and to read it
int i;
cin >> i;
float f=*(float&)&i;
[Standard disclamer about portability and making sure that int and float are the same size on your platform.]
This way you can output the value and read it back in without losing any precision. But it's not human readable when it's being stored.
1st of all: you can't convert floating to string and back without probably loosing a bit or two. As it is not 1-to-1 conversion as they use different base.
For preserving the best accuracy for floating point type:
std::string convert(float value)
{
std::stringstream ss;
ss << std::setprecision(std::numeric_limits<float>::digits10+1);
ss << value;
return ss.str();
}
Or more generic
template<typename FloatingPointType>
std::string convert(FloatingPointType value)
{
std::stringstream ss;
ss << std::setprecision(std::numeric_limits<FloatingPointType>::digits10+1);
ss << value;
return ss.str();
}
It would cut off digits you do not need but keep highest precision possible.
The OP wants C or C++, but if you happen to need a C# solution, use the "R" numeric formatting string, as in:
float x = 23.345466467f;
string str = x.ToString("R");
Note that "R" is short for "Round-trip". More info on MSDN.
精彩评论