如何将浮点数舍入到C中最接近的整数?

有没有办法在C中舍入数字?

我不想使用ceil和地板。 还有其他选择吗?

当我用Google搜索答案时,我遇到了这段代码:

(int)(num < 0 ? (num - 0.5) : (num + 0.5)) 

即使float num = 4.9,上面的行总是将值打印为4。

4.9 + 0.5是5.4,除非编译器严重损坏,否则不能四舍五入到4。

我刚刚确认Google搜索代码给出了4.9的正确答案。

 marcelo@macbookpro-1:~$ cat round.c #include  int main() { float num = 4.9; int n = (int)(num < 0 ? (num - 0.5) : (num + 0.5)); printf("%d\n", n); } marcelo@macbookpro-1:~$ make round && ./round cc round.c -o round 5 marcelo@macbookpro-1:~$ 

一般的解决方案是使用rint()并根据需要设置FLT_ROUNDS舍入模式。

我不确定这是个好主意。 该代码依赖于强制转换,我很确定精确的截断是未定义的。

 float result = (num - floor(num) > 0.5) ? ceil(num) : floor(num); 

我会说这是一个更好的方式(这基本上是Shiroko发布的),因为它不依赖于任何演员阵容。

我想你要找的是: int n = (d - floor(d) > 0.5) ? ceil(d) : floor(d); int n = (d - floor(d) > 0.5) ? ceil(d) : floor(d);

谷歌搜索的代码正常工作。 它背后的想法是,当小数小于.5时向下舍入,否则向上舍入。 (int)将float转换为一个只删除小数的int类型。 如果将.5添加到正数,则会转到下一个int。 如果你从负数中减去.5就会做同样的事情。

要在C中舍入float ,有3个函数可以满足需要。 推荐rintf()

 float nearbyintf(float x); 

nearbyint函数将其参数围绕浮点格式的整数值,使用当前的舍入方向,而不会引发“不精确”的浮点exception。 C11dr§7.12.9.32

要么

 float rintf(float x); 

rint函数与nearbyint函数(7.12.9.3)的不同之处仅在于,如果结果与参数的值不同,则rint函数可能会引发”不精确”浮点exception。 C11dr§7.12.9.42

要么

 float roundf(float x); 

round函数将它们的参数四舍五入为浮点格式的最接近的整数值,无论当前的舍入方向如何,都将中间情况舍入为零。 C11dr§7.12.9.62


 #include  #include  #include  void rtest(const char *fname, double (*f)(double x), double x) { printf("Clear inexact flag :%s\n", feclearexcept(FE_INEXACT) ? "Fail" : "Success"); printf("Set round to nearest mode:%s\n", fesetround(FE_TONEAREST) ? "Fail" : "Success"); double y = (*f)(x); printf("%s(%f) --> %f\n", fname,x,y); printf("Inexact flag :%s\n", fetestexcept(FE_INEXACT) ? "Inexact" : "Exact"); puts(""); } int main(void) { double x = 8.5; rtest("nearbyint", nearbyint, x); rtest("rint", rint, x); rtest("round", round, x); return 0; } 

产量

 Clear inexact flag :Success Set round to nearest mode:Success nearbyint(8.500000) --> 8.000000 Inexact flag :Exact Clear inexact flag :Success Set round to nearest mode:Success rint(8.500000) --> 8.000000 Inexact flag :Inexact Clear inexact flag :Success Set round to nearest mode:Success round(8.500000) --> 9.000000 Inexact flag :Exact 

OP的代码有什么弱点?

 (int)(num < 0 ? (num - 0.5) : (num + 0.5)) 
  1. 如果num的值不在int范围内,则cast (int)导致未定义的行为。

  2. num +/- 0.5导致不准确的答案时。 这不太可能,因为0.5double导致加法以比float更高的精度发生。 当num0.5具有相同的精度时,将0.5添加到数字可能会导致数字舍入答案。 (这不是OP的post的整数舍入。)例如:小于0.5的数字应该是每个OP的目标为0,但是num + 0.5导致1.0和最小的double精度之间的精确答案,小于1.0。 由于确切的答案是不可表示的,因此总和通常为1.0,导致答案不正确。 类似的情况发生在大数字上。


OP的困境是“即使float num =4.9 ,上面的行总是将值打印为4”。 如上所述,无法解释。 需要额外的代码/信息。 我怀疑OP可能使用了int num = 4.9;


 // avoid all library calls // Relies on UINTMAX_MAX >= FLT_MAX_CONTINUOUS_INTEGER - 1 float my_roundf(float x) { // Test for large values of x // All of the x values are whole numbers and need no rounding #define FLT_MAX_CONTINUOUS_INTEGER (FLT_RADIX/FLT_EPSILON) if (x >= FLT_MAX_CONTINUOUS_INTEGER) return x; // Positive numbers // Important: _no_ precision lost in the subtraction // This is the key improvement over OP's method if (x > 0) { float floor_x = (float)(uintmax_t) x; if (x - floor_x >= 0.5) floor_x += 1.0f; return floor_x; } if (x < 0) return -my_roundf(-x); return x; // x is 0.0, -0.0 or NaN } 

经过测试很少 - 我有时间会这样做。

您可以在fenv.h使用fesetround() (在C99中引入)。 可能的参数是宏FE_DOWNWARDFE_TONEARESTFE_TOWARDZEROFE_UPWARD但请注意,并非所有参数都必须定义 – 只有平台/实现支持的参数。 然后你可以在math.h (也是C99)中使用各种roundrintnearbyint函数。 这样,您可以设置一次所需的舍入行为,并调用相同的函数,无论该值是正还是负。

(例如lround你通常不需要设置正常使用的舍入方向,通常可以得到你想要的。)

 int round(double x) { return x >= 0.0 ? int(x + 0.5) : int(x - int(x-1) + 0.5) + int(x-1); } 

它会比带有ceil和floor的版本更快。

舍入值x到精度p,其中0

 float RoundTo(float x, float p) { float y = 1/p; return int((x+(1/(y+y)))*y)/y; } float RoundUp(float x, float p) { float y = 1/p; return int((x+(1/y))*y)/y; } float RoundDown(float x, float p) { float y = 1/p; return int(x*y)/y; } 

只需将0.5添加到数字并对其进行类型转换..然后通过类型将其打印为整数来打印它。否则你可以使用round()在其中传递参数作为相应的数字。

尝试移动上面解决方案中的括号,使其显示为:

 (int)(num < 0) ? (num - 0.5) : (num + 0.5) 

使用num作为4.9,它在我的机器上舍入为5。