通常情况下,
可以很容易地舍入到2位小数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中是可行的,但仅适用于整数;
int a = (int)(b+0.5)
所以,我要求如何做同样的事情,在正值上用2位小数而不是Integer来实现我之前说的用于打印。
答案 0 :(得分:2)
目前尚不清楚你是否真的希望&#34; 围绕半场&#34;或者更确切地说&#34; 从零开始的一半 &#34;,这需要对负值进行不同的处理。
单精度二进制float
精确到至少6个小数位,20为double
,因此通过DBL_EPSILON(在float.h中定义)轻推FP值将导致向上舍入到 n.nn5 值的下一个第100个printf( "%.2lf", x )
。不影响值 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
答案 1 :(得分:1)
[编辑] 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
等样本数与[{1}}的{{1}}值相近,假设为binary64。根据OP的要求,将该数字舍入到最接近的0.01应为2.56而不是2.57。
因此,只有0.125和0.625区域的数字完全中途并向下舍入而不是按照OP的要求向上舍入。建议接受并使用:
double
为了接近OP的目标,数字可能是A)测试结束时以0.125或0.625或B)略有增加。增幅最小的是
2.564999999999999947...
@Clifford找到了另一种微调方法。
[前回答将printf("%.2lf",variable); // This should be sufficient
四舍五入到最接近{0.01}的#include <math.h>
printf("%.2f", nextafter(x, 2*x));
倍数
典型的浮点使用类似binary64的格式,它使用base-2。 “舍入到最接近的数学0.01并且与0.0的关系”具有挑战性。
正如@Pascal Cuoq所提到的,像double
这样的浮点数通常只接近double
并且具有更精确的值,例如2.555
不一半方式。
下面的@BLUEPIXY解决方案是最好和实用的。
2.555
“round函数将其参数四舍五入到浮点数中最接近的整数值 格式,无论当前的舍入方向如何,都将中途的情况从零处舍入。“C11dr§7.12.9.6。
2.555000000000000159872...
方法有两个问题:它可能在错误的方向上舍入为负数(OP未指定),而整数通常具有更小的范围(x = round(100.0*x)/100.0;
到((int)(100 * (x + 0.005)) / 100.0)
)INT_MIN
。
仍有一些情况,例如当INT_MAX
最终接近1.12时真的应该是double
因为double x = atof("1.115");
,因为1.11
真的更接近{ {1}}而不是“中途”。
1.115
假设double
,OP未指定负数舍入。
答案 2 :(得分:1)
以下是将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 %.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;
}