如何将浮点数舍入到给定的小数精度

时间:2013-10-02 19:05:19

标签: c linux floating-point rounding

我需要将具有系统精度的浮点数转换为具有指定精度(例如3个小数位)的浮点数用于打印输出。 fprintf函数不足以满足要求,因为它不能正确地舍入某些数字。我尝试过的所有其他解决方案都失败了,因为当我转换回浮点数时,它们都会重新引入不需要的精度。例如:

float xf_round1_f(float input, int prec) {

    printf("%f\t",input);
    int trunc = round(input * pow(10, prec));
    printf("%f\t",(float)trunc);
    input=(float)trunc / pow(10, prec);
    printf("%f\n",input);
    return (input);

}

此函数将输入,截断的整数和输出打印到每一行,对于某些应截断为3位小数的数字,结果如下所示:

49.975002 49975.000000 49.974998

49.980000 49980.000000 49.980000

49.985001 49985.000000 49.985001

49.990002 49990.000000 49.990002

49.995003 49995.000000 49.994999

50.000000 50000.000000 50.000000

您可以看到第二步按预期工作 - 即使将“trunc”转换为float以进行打印 - 但只要我将其转换回float,精度就会返回。第1行和第6行说明了问题情况。

当然必须有一种方法可以解决这个问题 - 即使第一行结果仍然是49.975002,格式化的打印也会产生预期的效果,但在这种情况下存在一个真正的问题。

任何解决方案?

4 个答案:

答案 0 :(得分:4)

二进制浮点不能完全代表大多数十进制数字。每个二进制浮点数通过将整数乘以2的幂来形成。对于float,IEEE-754 32位二进制浮点的通用实现,该整数必须在(-2 24 ,2 24 )中。没有整数 x 和整数 y ,因此 x •2 y 等于49.975。因此,当您将49975除以1000时,结果必须为近似值。

如果您只需要为输出格式化数字,则可以使用通常的fprintf格式说明符来执行此操作。如果您需要精确计算这些数字,您可以通过将它们缩放为可表示的值并以浮点或整数运算来执行此操作,具体取决于您的需要。

答案 1 :(得分:1)

编辑:您似乎只关心打印结果。 printf通常足够聪明,可以根据您指定的位数进行适当的舍入。如果您提供"%.3f"格式,您可能会获得所需内容。

<小时/> 如果您的唯一问题是低于所需数量的情况,您可以通过使所有内容高于所需数字来轻松修复它。不幸的是,这增加了答案的绝对误差;即使是之前确切的结果,例如50.000现已关闭。

只需将此行添加到函数末尾:

input=nextafterf(input, input*1.0001);

http://ideone.com/iHNTzs

中查看此操作
49.975002   49975.000000    49.974998   49.975002
49.980000   49980.000000    49.980000   49.980003
49.985001   49985.000000    49.985001   49.985004
49.990002   49990.000000    49.990002   49.990005
49.995003   49995.000000    49.994999   49.995003
50.000000   50000.000000    50.000000   50.000004

答案 2 :(得分:1)

如果您需要精确表示小数点后三位数的所有小数部分,则可以千分之一工作。使用整数数据类型表示所有中间结果的实际数量的一千倍。

答案 3 :(得分:0)

定点数。这是您将实际数字保持为宽精度整数格式的地方,例如长或长。而且你还保留小数位数。然后,您还需要使用小数位来缩放固定点数的方法。以及转换为字符串的方法。

你遇到麻烦的原因是1/10不能代表2(1/2,1 / 4,1 / 8等)的分数幂。这与1/3是基数10(0.33333 ...)中的重复小数的原因相同。