简体   繁体   中英

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 precision. 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支持printf中的%a格式,允许在不损失精度的情况下输出double的内容。

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.

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:

  1. 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.
  2. Repeatedly remove the integer portion of val and multiply by 0x10 to get the output digits.
  3. When val reaches 0, you're done.

Conversion in the opposite direction is likewise easy.

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.

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 .

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 technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM