3

double我正在开发一种软​​件,它可以在文本和内部 ( ) 表示之间转换测量的数字。该过程的一个必要部分是根据测量的统计不确定性生成具有正确小数精度的文本表示。所需的精度随数字而变化,其中的最低有效数字可以是任何地方,包括(十进制)单位位置的左侧。

正确舍入对于此过程至关重要,其中“正确”意味着根据当时有效的浮点舍入模式,或至少在明确定义的舍入模式下。因此,我需要小心(阅读:避免)对正在处理的数字执行中间算术,因为舍入甚至对数字内部表示中的最低有效位也是敏感的。

如果我首先计算所需表示中的有效位数,我认为我可以使用 printf 系列函数相当好地完成几乎所有需要的格式化:

sprintf(buffer, "%.*e", num_sig_figs - 1, number);

然而,到目前为止,有一类极端情况让我失望:测量数字中的最高有效(十进制)数字位于所需精度表示的最低有效数字的右侧一位。在这种情况下,四舍五入应在所需结果中产生最小(也是唯一)有效数字为 0 或 1,但我无法设计一种方法以可移植(*)方式执行舍入而不会有风险改变结果。这类似于 MPFR 函数mpfr_prec_round()可以做的事情,除了它以二进制精度工作,而我需要使用十进制精度。

例如,在默认的舍入模式下(四舍五入到最近的舍入到偶数):

  • 0.5 表示为单位 (10^0) 精度应为“0”或“0e+00”
  • 654 表示为千 (10^3)​​ 精度应为“1e+03”
  • 0.03125 表示为十分之一 (10^-1) 精度应为“0”或“0e-01”甚至“0e+00”

(*) 这里的“可移植”是指代码准确地表达了标准的可移植 C99(或更好的 C90)中的计算。据了解,实际结果可能取决于机器细节,它应该取决于(并与)生效的浮点舍入模式。

我有什么选择?

4

1 回答 1

2

一种始终有效的简单(尽管效率相当低)的方法是将完整的精确十进制值打印为字符串,然后手动以十进制进行舍入。这可以通过类似的东西来实现

snprintf(buf, sizeof buf, "%.*f", DBL_MANT_DIG-DBL_MIN_EXP, x);

我希望我得到了正确的精度。这个想法是,每增加一个尾数位,每增加一个 2 的负幂,就多占用一个小数位。

通过获得的十进制值是精确的这一事实,您可以避免双重舍入的问题。

请注意,双舍入仅在默认舍入模式(最近)中重要。在其他模式下,双舍入获得的结果与单次舍入步骤获得的结果相同,因此您可以根据需要走很多捷径。

如果我想到它们,我可能会在稍后发布更好的解决方案。printf请注意,上述解决方案仅适用于函数族能够打印精确小数的高质量实现。例如,在 MSVCRT 和其他低质量实现上,甚至在一些符合要求的实现上,它都会失败。

于 2013-05-20T18:07:32.147 回答