一般来说,
很容易四舍五入到小数点后两位printf("%.2lf",<variable>);
但是,舍入系统通常会舍入到最接近偶数的。例如,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中是可行的,但只适用于Integer;
int a = (int)(b+0.5)
所以,我问的是如何做同样的事情与上面的2位小数的正值,而不是整数,以实现我之前说的打印。
不清楚您是否真的想要"舍入一半",还是"舍入一半零",这需要对负值进行不同的处理。
单精度二进制float
至少精确到小数点后6位,double
精确到20位,因此通过DBL_EPSILON(在float.h中定义)推动FP值将导致printf( "%.2lf", x )
对n进行四舍五入到下一个100位。nn5 的值。不影响非值的显示值。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_MAX
到DBL_MAX
。(仍然应该做更多的单元测试)。
它依赖于FLT_RADIX == 2
,这是常见的。
#include <float.h>
#include <math.h>
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 %.2fn", "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;
}
[Edit] OP澄清,只有打印的值需要四舍五入到小数点后两位。
OP观察到每"四舍五入到偶数"或"四舍五入到零"的数字"一半"是误导性的。在100个"半途"数字中,比如0.005、0.015、0.025……0.995,只有4个典型的正好"一半":0.125,0.375,0.625,0.875。这是因为浮点数格式使用基数2,而像2.565这样的数字不能精确表示。
相反,假设binary64, 2.565
等样本数具有与2.564999999999999947...
最接近的double
值。该数字四舍五入到最接近0.01的值应该是2.56,而不是op期望的2.57。
因此,只有以0.125和0.625结尾的数字正好位于的中间位置,并按op的要求向下四舍五入,而不是向上。建议接受并使用:
printf("%.2lf",variable); // This should be sufficient
为了接近OP的目标,可以A)测试以0.125或0.625结尾的数字,或者B)稍微增加。最小的增长是
#include <math.h>
printf("%.2f", nextafter(x, 2*x));
另一个轻推方法是@Clifford。
[将double
舍入到最接近于0.01的double
倍数的前一个答案]
典型的浮点数使用像binary64这样的以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没有指定),并且整数通常具有比double
小得多的范围(INT_MIN
到INT_MAX
)。
仍然有一些情况,比如当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
OP没有指定负数的舍入,假设y = -f(-x)
。