【问题标题】:Is there a function to round a float in C or do I need to write my own?是否有一个函数可以在 C 中舍入一个浮点数,还是我需要自己编写?
【发布时间】:2009-01-30 20:03:52
【问题描述】:

是否有一个函数可以在 C 中舍入一个浮点数,还是我需要自己编写?

float conver = 45.592346543;

我想将实际值四舍五入到小数点后一位,conver = 45.6

【问题讨论】:

    标签: c floating-point rounding


    【解决方案1】:

    正如 Rob 所说,您可能只想打印浮点数到小数点后 1 位。在这种情况下,您可以执行以下操作:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
      float conver = 45.592346543;
      printf("conver is %0.1f\n",conver);
      return 0;
    }
    

    如果您想实际对存储的值进行四舍五入,那就有点复杂了。一方面,您的一位小数位表示很少有精确的浮点模拟。如果你只是想尽可能靠近,这样的事情可能会奏效:

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    int main()
    {
      float conver = 45.592346543;
      printf("conver is %0.1f\n",conver);
    
      conver = conver*10.0f;
      conver = (conver > (floor(conver)+0.5f)) ? ceil(conver) : floor(conver);
      conver = conver/10.0f;
    
      //If you're using C99 or better, rather than ANSI C/C89/C90, the following will also work.
      //conver = roundf(conver*10.0f)/10.0f;
    
      printf("conver is now %f\n",conver);
      return 0;
    }
    

    我怀疑第二个示例是您要查找的内容,但为了完整起见,我将其包含在内。如果您确实需要在内部以这种方式表示您的数字,而不仅仅是在输出上,请考虑改用 fixed-point representation

    【讨论】:

    • 四舍五入似乎工作正常,但例如四舍五入 45.569346543;是 45.599998 .... 或 45.5 和 *1.0f .... 我更仔细地想,需要再次阅读 floor 和 ceil。谢谢大家。
    • 它来自浮点不准确,我改为双精度,效果很好。谢谢。
    • 只是重申马特 J 的结束评论,我不确定你是否吸收了:45.6 不能以任何二进制浮点格式精确表示,所以这不是存储的内容,即使你使用 double .如果您的程序现在正在打印“45.6”,那是因为输出例程正在为您四舍五入。
    • (conver &gt;= (floor(conver)+0.5f)) ? ceil(conver) : floor(conver) 等同于 floor(conver+0.5f)(我认为,您的意思是 &gt;=,而不是 &gt;)。
    • 另外最好这样做:conver&gt;0f ? floor(conver+0.5f) : ceil(conver-0.5f) — 也可以处理底片。
    【解决方案2】:

    当然,你可以使用 roundf()。如果你想四舍五入到一位小数,那么你可以这样做:roundf(10 * x) / 10

    【讨论】:

    • 很好,其他人都忽略了提问者没有要求四舍五入到最接近整数的事实。需要注意的是,由于浮点数不精确。打印时,您可能会看到示例中的“45.59999”。
    • 一个不错的更通用的解决方案是: double f(double x, int decimal_points) { int n = pow(10, decimal_points);返回roundf(n * x)/ n; }
    • 函数 _f 中引用的未解析外部符号 _roundf 包含了 math.h 但它不喜欢 roundf() 我在 VS .NET 中,foundf 仅适用于 linux?
    • Tommy,roundf() 是在 C99 中定义的,所以每个兼容的编译器都应该支持它。也许您没有链接到数学库?
    • 我认为新的视觉工作室没有做出任何努力来支持 C99。
    【解决方案3】:
    #include <math.h>
    
    double round(double x);
    float roundf(float x);
    

    不要忘记使用 -lm 链接。另请参见 ceil()、floor() 和 trunc()。

    【讨论】:

    • 四舍五入到最接近的整数...不是他要求的。
    • 没错,我超前了。我对爱德华的回答投了赞成票。
    【解决方案4】:

    只是为了概括 Rob 的回答,如果您在输出上这样做,您仍然可以使用与sprintf() 相同的界面。

    不过,我认为还有另一种方法可以做到这一点。您可以尝试使用ceil()floor() 进行上下舍入。一个不错的技巧是添加 0.5,因此任何超过 0.5 的内容都会向上取整,但低于 0.5 的任何内容都会向下取整。 ceil()floor() 仅适用于 doubles。

    编辑:另外,对于浮点数,您可以使用 truncf() 截断浮点数。同样的 +0.5 技巧应该可以进行精确的舍入。

    【讨论】:

    • 您可以分别使用 ceilf()floorf()roundf() 进行浮动。
    • “一个不错的技巧是添加 0.5”,在很多情况下都会失败:see comment
    【解决方案5】:

    打印一个四舍五入的值,@Matt J 很好地回答了这个问题。

    float x = 45.592346543;
    printf("%0.1f\n", x);  // 45.6
    

    由于大多数浮点 (FP) 是基于 二进制,当数学上正确的答案是x.1, x.2, ....

    将 FP 号转换为 最近 0.1 是另一回事。

    溢出:首先缩放 10(或 100、1000 等)的方法可能会溢出较大的 x

    float round_tenth1(float x) {
      x = x * 10.0f;
      ...
    }
    

    双舍入:当中间和 x*10.0f + 0.5f 向上舍入一个新整数时,添加 0.5f 然后使用 floorf(x*10.0f + 0.5f)/10.0 返回错误的结果。

    // Fails to round 838860.4375 correctly, comes up with 838860.5 
    // 0.4499999880790710449 fails as it rounds to 0.5
    float round_tenth2(float x) {
      if (x < 0.0) {
        return ceilf(x*10.0f + 0.5f)/10.0f;
      }
      return floorf(x*10.0f + 0.5f)/10.0f;
    }
    
    float x 远大于INT_MAX 时,

    强制转换int 存在明显问题。


    使用roundf() 和家人,在&lt;math.h&gt; 中可用是最好的方法。

    float round_tenthA(float x) {
      double x10 = 10.0 * x;
      return (float) (round(x10)/10.0);
    }
    

    为避免使用double,只需测试数字是否需要四舍五入。

    float round_tenthB(float x) {
      const float limit = 1.0/FLT_EPSILON;
      if (fabsf(x) < limit) {
        return roundf(x*10.0f)/10.0f;
      }
      return x;
    }
    

    【讨论】:

      【解决方案6】:

      有一个round() 函数,还有fround(),它将舍入到最接近的整数,以双精度表示。但这不是你想要的。

      我遇到了同样的问题,写了这个:

      #include <math.h>
      
         double db_round(double value, int nsig)
      /* ===============
      **
      ** Rounds double <value> to <nsig> significant figures.  Always rounds
      ** away from zero, so -2.6 to 1 sig fig will become -3.0.
      **
      ** <nsig> should be in the range 1 - 15
      */
      
      {
          double     a, b;
          long long  i;
          int        neg = 0;
      
      
          if(!value) return value;
      
          if(value < 0.0)
          {
              value = -value;
              neg = 1;
          }
      
          i = nsig - log10(value);
      
          if(i) a = pow(10.0, (double)i);
          else  a = 1.0;
      
          b = value * a;
          i = b + 0.5;
          value = i / a;
      
          return neg ? -value : value;
      } 
      

      【讨论】:

        【解决方案7】:

        你可以使用#define round(a) (int) (a+0.5) 作为宏 所以当你写 round(1.6) 时它返回 2 并且每当你写 round(1.3) 它返回 1。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多