将正值舍入到C中的2位小数

通常,舍入到小数点后2位非常容易

printf("%.2lf",); 

但是,舍入系统通常会舍入到最接近的偶数 。 例如,

 2.554 -> 2.55 2.555 -> 2.56 2.565 -> 2.56 2.566 -> 2.57 

而我想要实现的是

 2.555 -> 2.56 2.565 -> 2.57 

事实上, 四舍五入在C中是可行的,但仅对于整数;

 int a = (int)(b+0.5) 

所以,我要问的是如何在正值上用2位小数而不是整数来做同样的事情来实现我之前说的打印

目前尚不清楚你是否真的想要“ 四舍五入 ”,或者更确切地说“ 从零开始一半 ”,这需要对负值进行不同的处理。

单精度二进制float精确至少6个小数位,20表示精确倍数,因此通过DBL_EPSILON(在float.h中定义)轻推FP值将导致通过printf( "%.2lf", x )向下舍入到下一个100 printf( "%.2lf", x ) n.nn5值。 不影响值n.nn5的显示值

 double x2 = x * (1 + DBL_EPSILON) ; // round half-away from zero printf( "%.2lf", x2 ) ; 

对于不同的舍入行为:

 double x2 = x * (1 - DBL_EPSILON) ; // round half-toward zero double x2 = x + DBL_EPSILON ; // round half-up double x2 = x - DBL_EPSILON ; // round half-down 

以下是精确的代码,将double舍入到最接近的0.01 double

代码函数如x = round(100.0*x)/100.0; 除了处理使用操作以确保100.0的缩放完全没有精度损失。

可能这比OP感兴趣的代码更多,但确实有效。

它适用于整个double范围-DBL_MAXDBL_MAX 。 (还是应该做更多的unit testing)。
它取决于FLT_RADIX == 2 ,这很常见。

 #include  #include  void r100_best(const char *s) { double x; sscanf(s, "%lf", &x); // Break x into whole number and fractional parts. // Code only needs to round the fractional part. // This preserves the entire `double` range. double xi, xf; xf = modf(x, &xi); // Multiply the fractional part by N (256). // Break into whole and fractional parts. // This provides the needed extended precision. // N should be >= 100 and a power of 2. // The multiplication by a power of 2 will not introduce any rounding. double xfi, xff; xff = modf(xf * 256, &xfi); // Multiply both parts by 100. // *100 incurs 7 more bits of precision of which the preceding code // insures the 8 LSbit of xfi, xff are zero. int xfi100, xff100; xfi100 = (int) (xfi * 100.0); xff100 = (int) (xff * 100.0); // Cast here will truncate (towards 0) // sum the 2 parts. // sum is the exact truncate-toward-0 version of xf*256*100 int sum = xfi100 + xff100; // add in half N if (sum < 0) sum -= 128; else sum += 128; xf = sum / 256; xf /= 100; double y = xi + xf; printf("%6s %25.22f ", "x", x); printf("%6s %25.22f %.2f\n", "y", y, y); } int main(void) { r100_best("1.105"); r100_best("1.115"); r100_best("1.125"); r100_best("1.135"); r100_best("1.145"); r100_best("1.155"); r100_best("1.165"); return 0; } 

[编辑] OP澄清说只有打印值需要四舍五入到小数点后两位。

OP的观察结果是,对于“圆形到均匀”或“远离零”的数字“中途”舍入数字是误导性的。 在100个“中途”数字中,如0.005,0.015,0.025,… 0.995,只有4个通常正好是 “中途”:0.125,0.375,0.625,0.875。 这是因为浮点数格式使用base-2,而像2.565这样的数字无法准确表示。

相反,像2.565这样的样本数具有最接近的double 2.564999999999999947...2.564999999999999947...假设为binary64 。 根据OP的要求,将该数字舍入到最接近的0.01应该是2.56而不是2.57。

因此,只有以0.125和0.625区域结尾的数字恰好是中途和向下舍入而不是按照OP所希望的那样向上。 建议接受并使用:

 printf("%.2lf",variable); // This should be sufficient 

为了接近OP的目标,数字可以是A)测试结束时以0.125或0.625或B)稍微增加。 增幅最小的是

 #include  printf("%.2f", nextafter(x, 2*x)); 

使用@Clifford可以找到另一种轻推方法。


[以前的答案将double入到最接近0.01的倍数倍]

典型的浮点使用binary64这样的格式,它使用base-2。 “舍入到最接近的数学0.01并且与0.0的关系”具有挑战性。

正如@Pascal Cuoq所提到的,像2.555这样的浮点数通常只接近2.555并且具有更精确的值,如2.555000000000000159872...不是一半。

下面的@BLUEPIXY解决方案是最好和实用的。

 x = round(100.0*x)/100.0; 

“圆函数将它们的参数四舍五入到浮点格式的最接近的整数值,无论当前的舍入方向如何,都将中途的情况四舍五入。” C11dr§7.12.9.6。

((int)(100 * (x + 0.005)) / 100.0)方法有两个问题:它可能在错误的方向上舍入为负数(OP未指定),而整数通常具有更小的范围( INT_MININT_MAX那个double


还有一些情况,比如double x = atof("1.115"); 最终接近1.12时真的应该是1.11因为1.115 ,因为double真正接近1.11而不是“中途”。

 string x rounded x 1.115 1.1149999999999999911182e+00 1.1200000000000001065814e+00 

假设y = -f(-x) ,OP没有指定负数的舍入。