在C90 / 99中舍入到指定的绝对小数精度

时间:2013-05-20 17:10:49

标签: c rounding

我正致力于开发软件,除其他外,还可以在文本和内部(double)表示之间转换测量数字。该过程的必要部分是基于测量的统计不确定性产生具有正确小数精度的文本表示。所需的精度随数字而变化,其中最不重要的数字可以是任何位置,包括(十进制)单位的左边。

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

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

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

到目前为止,有一类角落案件使我失败了:测量数字中最重要的(十进制)数字是所需精度表示的最低有效数字的一个位置。在这种情况下,舍入应该将期望结果中的最小(且唯一)有效数字产生为0或1,但是我无法设计以便携式(*)方式执行舍入的方法而没有风险改变结果。这类似于MPFR函数mpfr_prec_round()可以做的,除了它以二进制精度工作,而我需要使用小数精度。

例如,在默认的舍入模式中(舍入为舍入为偶数的舍入为圆形):

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

(*)这里的“Portable”意味着代码在标准的便携式C99(或更好的C90)中准确地表达了计算。据了解,实际结果可能取决于机器细节,依赖(并与之一致)浮点舍入模式。

我有哪些选择?

1 个答案:

答案 0 :(得分:2)

一种简单(尽管相当低效)的方法总是可以将完整的精确十进制值打印为字符串,然后手动进行十进制舍入。这可以通过

之类的东西来实现
snprintf(buf, sizeof buf, "%.*f", DBL_MANT_DIG-DBL_MIN_EXP, x);

我希望我的精确度合适。这个想法是每个额外的尾数位,以及每个额外的2的负幂,占用一个额外的小数位。

通过获得的十进制值是精确的,可以避免双舍入的问题。

请注意,双舍入仅在默认舍入模式(最近)中很重要。在其他模式中,双舍入获得与单个舍入步骤相同的结果,因此如果您愿意,可以使用许多快捷键。

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