将float转换为字符串而不会丢失精度

时间:2010-12-16 10:55:55

标签: c++ c type-conversion

我想将浮点值存储到字符串中,而不会丢失或添加任何单个精度数字。

例如,如果我的浮点值是23.345466467,我希望我的字符串有str =“23.345466467”的确切数字。

我尝试使用%f的CString格式函数。它只给出了前6个精度。 或者如果我使用%10,如果我的浮点值精度小于10,则会增加一些垃圾精度。我想在我的字符串中获得精确的浮点值。怎么做?

10 个答案:

答案 0 :(得分:8)

C99支持%a中的printf格式,允许输出双精度内容而不会损失精度。

答案 1 :(得分:7)

这取决于您的浮点值23.345466467是否可以准确表示(可能不是)

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Why Floating-Point Numbers May Lose Precision

我也会质疑为什么你需要这样做?你打算用什么字符串表示?你知道双重和小数类型吗?

[ 未经测试 :您可以尝试进行加倍,然后使用“%d”也许这会吸引额外的'后卫'数字'但它仍然赢了'适用于所有价值观]

答案 2 :(得分:7)

请参阅http://randomascii.wordpress.com/2012/03/08/float-precisionfrom-zero-to-100-digits-2/中的详细讨论。

简短的回答是最低精度如下:

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

或等效地使用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

答案 3 :(得分:2)

根据定义float唯一所需的(十进制)数字代表任何std::numeric_limits<float>::maxdigits10float格式无法区分0.00.0000,因此此常量是您需要的最大值。

现在,请注意我说唯一。这不是完全。这意味着如果你写两个不同的二进制值,你将得到两个不同的十进制表示。这也意味着如果你回读这样的十进制表示,它不能与任何其他值混淆,因此你得到了之前的二进制值。通常,这两种保证就足够了。

[编辑] std::numeric_limits<float>::digits10表示相反的概念:最大小数位数,使得十进制 - >二进制 - >小数保证完全正确。

答案 4 :(得分:2)

其他人已经评论说23.345466467不存在浮点数,但是如果您的目标只是浮点值的往返转换而存在而不会意外地略微改变它们的值,您可以使用snprintf和{ {1}}至少strtod个位置(POSIX,但不是普通的ISO C,确保此往返是精确的)或以十六进制而不是十进制打印浮点数。 C99具有DECIMAL_DIG格式说明符,用于以十六进制格式打印浮点数,但如果您不能依赖C99,则可以轻松编写自己的格式。与十进制不同,用于打印十六进制浮点数的朴素算法可以正常工作。它就像:

  1. 按2的幂进行缩放以将值放在%a范围内。 2的幂将成为结果中的指数。
  2. 反复删除0x8 <= val < 0x10的整数部分并乘以val以获取输出数字。
  3. 0x10达到0时,您就完成了。
  4. 相反方向的转换同样容易。

答案 5 :(得分:0)

也许您使用fprintf()(from)将浮点数转换为字符串。 但是在矫揉造作之后,精确度可能会立即失去,因为'flaot'和'double'的精度有限。有人必须证实这一点。

答案 6 :(得分:0)

最好的方法是存储其二进制表示,如@pgm所示。但是,您也可以使用十进制表示法存储它,但使用句点表示法,例如:

23.5095446(1545855463)

通过这种方式,它们可以以某种方式存储“无损”,但需要非常仔细的编码。

答案 7 :(得分:0)

您是否正在存储它以便以后可以重新阅读并将其用作浮动?或者你关心字符串说的是什么?正如其他人所说,你需要编写二进制表示而不是base10。或者你可能有点棘手,做这样的事情

float f=23.345466467
int i=*(int*)&f; //re-interpret the bits in f as an int
cout << i;

并阅读

int i;
cin >> i;
float f=*(float&)&i;

[关于可移植性的标准放大器,并确保您的平台上的int和float大小相同。]

通过这种方式,您可以输出值并将其读回,而不会丢失任何精度。但是当它被存储时,它不是人类可读的。

答案 8 :(得分:-1)

在C#中,使用“R”数字格式字符串,如:

float x = 23.345466467f;
string str = x.ToString("R");

请注意,“R”是“往返”的缩写。有关MSDN的更多信息。

答案 9 :(得分:-3)

首先:你不能将浮动转换为字符串和返回而不会丢失一两个。由于它们使用不同的基础,因此不是1对1的转换。

为了保持浮点类型的最佳精度:

std::string convert(float value)
{
  std::stringstream ss;
  ss << std::setprecision(std::numeric_limits<float>::digits10+1);
  ss << value;
  return ss.str();
}

或更通用的

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();
}

它会切断你不需要的数字,但可以保持最高精度。