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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2570934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:02:34  来源:igfitidea点击:

How to round floating point numbers to the nearest integer in C?

crounding

提问by webgenius

Is there any way to round numbers in C?

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

I do not want to use ceil and floor. Is there any other alternative?

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

I came across this code snippet when I Googled for the answer:

我在 Google 上搜索答案时遇到了这个代码片段:

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

The above line always prints the value as 4 even when float num =4.9.

即使在 float num =4.9 时,上面的行也始终将值打印为 4。

回答by Marcelo Cantos

4.9 + 0.5 is 5.4, which cannot possibly round to 4 unless your compiler is seriously broken.

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

I just confirmed that the Googled code gives the correct answer for 4.9.

我刚刚确认谷歌代码给出了 4.9 的正确答案。

marcelo@macbookpro-1:~$ cat round.c 
#include <stdio.h>

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:~$

回答by chux - Reinstate Monica

To round a floatin C, there are 3 <math.h>functions to meet the need. Recommend rintf().

为了float在 C 中舍入 a ,有 3 个<math.h>函数可以满足需要。推荐rintf()

float nearbyintf(float x);

The nearbyintfunctions round their argument to an integer value in floating-point format, using the current rounding direction and without raising the ‘‘inexact'' floating point exception. C11dr §7.12.9.3 2

这些nearbyint函数使用当前的舍入方向将其参数舍入为浮点格式的整数值,并且不会引发“不精确”浮点异常。C11dr §7.12.9.3 2

or

或者

float rintf(float x);

The rintfunctions differ from the nearbyintfunctions (7.12.9.3) only in that the rintfunctions may raise the ‘‘inexact'' floating-point exception if the result differs in value from the argument. C11dr §7.12.9.4 2

这些rint函数与nearbyint函数 (7.12.9.3) 的不同之处仅在于,rint如果结果与参数的值不同,函数可能会引发“不精确”浮点异常。C11dr §7.12.9.4 2

or

或者

float roundf(float x);

The roundfunctions round their argument to the nearest integer value in floating-point format, rounding halfway cases away from zero, regardless of the current rounding direction. C11dr §7.12.9.6 2

这些round函数将它们的参数四舍五入到最接近的浮点格式整数值,将中间情况从零舍入,而不管当前的舍入方向如何。C11dr §7.12.9.6 2



Example

例子

#include <fenv.h>
#include <math.h>
#include <stdio.h>

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;
}

Output

输出

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


What is weak about OP's code?

OP 的代码有什么弱点?

(int)(num < 0 ? (num - 0.5) : (num + 0.5))
  1. Should numhave a value not near the intrange, the cast (int)results in undefined behavior.

  2. When num +/- 0.5results in an inexact answer. This is unlikely here as 0.5is a doublecausing the addition to occur at a higher precision than float. When numand 0.5have the same precision, adding 0.5to a number may result in numerical roundedanswer. (This is not the whole number rounding of OP's post.) Example: the number just less than 0.5 should round to 0 per OP's goal, yet num + 0.5results in an exact answer between 1.0 and the smallest doublejust less than 1.0. Since the exact answer is not representable, that sum rounds, typically to 1.0 leading to an incorrect answer. A similar situation occurs with large numbers.

  1. 应该num有一个不在int范围附近的值,转换会(int)导致未定义的行为。

  2. num +/- 0.5导致不准确的答案时。这是不可能的这里0.5double导致除了比更高的精度进行float。当num0.5具有相同的精度时,添加0.5到一个数字可能会导致数字四舍五入的答案。(这不是 OP 帖子的整数四舍五入。)示例:根据 OP 的目标,小于 0.5 的数字应四舍五入为 0,但会num + 0.5导致精确答案介于 1.0 和double小于 1.0的最小值之间。由于无法表示确切的答案,因此该总和通常会舍入到 1.0,从而导致错误答案。类似的情况发生在大数上。



OP's dilemma about "The above line always prints the value as 4 even when float num =4.9." is not explainable as stated. Additional code/information is needed. I suspect OP may have used int num = 4.9;.

OP 的困境是“即使在float num =4.9. 无法解释如所述。需要额外的代码/信息。我怀疑 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;
  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
}

Tested little - will do so later when I have time.

测试很少 - 稍后我有时间时会这样做。

回答by Dan Story

A general solution is to use rint()and set the FLT_ROUNDSrounding mode as appropriate.

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

回答by Puppy

I'm not sure that's such a good idea. That code depends on casts, and I'm fairly sure that the exact truncation is undefined.

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

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

I'd say that this is a much better way (which is basically what Shiroko posted) since it doesn't depend on any casts.

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

回答by datdo

the googled code works correctly. The idea behind it is that you round down when the decimal is less than .5 and round up otherwise. (int)casts the float into a int type which just drops the decimal. If you add .5 to a positive num, you get drop to the next int. If you subtract .5 from a negative it does the same thing.

googled 代码工作正常。其背后的想法是当小数点小于 0.5 时向下舍入,否则向上舍入。 (int)将 float 转换为 int 类型,该类型仅删除小数。如果将 0.5 添加到正数,则会下降到下一个整数。如果从负数中减去 0.5,它会做同样的事情。

回答by Shiroko

I think what you're looking for is: int n = (d - floor(d) > 0.5) ? ceil(d) : floor(d);

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

回答by Arkku

You may be able to use fesetround()in fenv.h(introduced in C99). The possible arguments are the macros FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO, and FE_UPWARDbut note that not all of them are necessarily defined - only the ones supported by the platform/implementation are. Then you can use the various round, rintand nearbyintfunctions in math.h(also C99). This way you can set the desired rounding behaviour once and call the same function regardless of whether or not the value is positive or negative.

您也许可以使用fesetround()in fenv.h(在 C99中引入)。可能的参数是宏FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO,FE_UPWARD但请注意,并非所有这些都必须定义 - 只有平台/实现支持的参数。然后你可以使用各种round,rintnearbyint函数math.h(也是C99)。通过这种方式,您可以一次设置所需的舍入行为并调用相同的函数,而不管该值是正数还是负数。

(With e.g. lroundyou usually need not even set the rounding direction for normal use to usually get what you want.)

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

回答by Ekimov Alexander

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

It will be faster, than a version with ceil and floor.

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

回答by JJussi

Round value x to precision p, where 0 < p < infinite. (f.ex. 0.25, 0.5, 1, 2,…)

将值 x 舍入到精度 p,其中 0 < p < 无穷大。(例如 0.25, 0.5, 1, 2,...)

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;
}

回答by ravi kumar sharma

just add 0.5 to the number and typecast it.. and print it by type casting it in integer.. otherwise you can go with round() inside which just pass the argument as the respective number.

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