如何打印浮点值以供以后以完美的精度进行扫描?

ein*_*ica 6 c floating-point precision numeric

假设我有一个floator类型的浮点值double(即典型机器上的 32 位或 64 位)。我想将此值打印为文本(例如,打印到标准输出流),然后在其他一些过程中,将其扫描回 -fscanf()如果我使用的是 C,或者istream::operator>>()如果我使用的是 C++。但是-我需要扫描的浮子最终被准确,等同于原始值(最多相同值的等价表示)。此外,打印的值应该很容易阅读 - 对人类来说 - 作为浮点数,即我不想打印 0x42355316 并将其重新解释为 32 位浮点数。

我该怎么做?我假设(C 和 C++)的标准库是不够的,但也许我错了。我想足够数量的十进制数字可能能够保证低于精度阈值的错误 - 但这与保证舍入/截断会按照我想要的方式发生不同。

笔记:

  • 扫描不必完全准确,只需扫描原始值即可。
  • 如果它更容易,您可以假设该值是一个数字而不是无穷大。
  • 非正常支持是需要的,但不是必需的;如果我们得到一个异常,失败应该是显而易见的。

Eri*_*hil 4

首先,您应该使用%a带有fprintf和 的格式fscanf。这就是它的设计目的,如果实现使用二进制浮点,C 标准要求它能够工作(再现原始数字)。

\n

如果做不到这一点,您应该打印一个float至少FLT_DECIMAL_DIG有有效数字的 a 和一个double至少DBL_DECIMAL_DIG有有效数字的 a。这些常量的定义如下<float.h>

\n
\n

\xe2\x80\xa6\xc2\xa0 十进制位数n,这样任何具有p基数b位的浮点数都可以四舍五入为具有n 个十进制位数的浮点数,并且可以在不更改值的情况下再次舍入, \xe2\x80\xa6 [ b是用于浮点格式的基数,在 中定义FLT_RADIXp是格式中基数b的位数。]

\n
\n

例如:

\n
    printf("%.*g\\n", FLT_DECIMAL_DIG, 1.f/3);\n
Run Code Online (Sandbox Code Playgroud)\n

或者:

\n
#define QuoteHelper(x)  #x\n#define Quote(x)        QuoteHelper(x)\n\xe2\x80\xa6\n    printf("%." Quote(FLT_DECIMAL_DIG) "g\\n", 1.f/3);\n
Run Code Online (Sandbox Code Playgroud)\n

<limits>在 C++ 中,这些常量在as中定义std::numeric_limits<Type>::max_digits10,其中Typefloatordouble或其他浮点类型。

\n

请注意,C 标准仅建议通过十进制数字进行此类往返工作;它不需要它。例如,C 2018 5.2.4.2.2 15 在标题 \xe2\x80\x9cRecommended Practice\xe2\x80\x9d 下表示:

\n
\n

从(至少)double到带有DECIMAL_DIG数字的十进制的转换应该是恒等函数。[DECIMAL_DIG相当于实现中支持的最宽浮点格式。FLT_DECIMAL_DIG]DBL_DECIMAL_DIG

\n
\n

相反,如果您使用%a, 且FLT_RADIX是 2 的幂(意味着实现使用的浮点基数是 2、16 或另一个 2 的幂),则 C 标准要求扫描使用 equals 生成的数字的%a结果原来的号码。

\n