【问题标题】:how to do rounding in C?如何在C中进行舍入?
【发布时间】:2013-06-08 14:38:36
【问题描述】:

我有一个代码示例:

float f = 3.55f;
printf("%.1f\n", f);

结果是 3.5,而不是所需的 3.6。

float delta = 1e-7;
float f = 3.55f;
printf("%.1f\n", f+delta);

现在结果是 3.6,但是当 f 是 0.0499999f;

printf("%.1f\n", f+delta);

结果是 0.1,而不是 0.0。

我需要一个将 3.55 转换为 3.6、0.0499999 转换为 0.0 的函数,有人提供线索吗?

【问题讨论】:

  • 在第二个例子中,你确定仅仅声明另一个变量会改变printf()的行为吗?
  • 尝试添加所需精度的一半,例如f + 0.05,然后用%.1f(或0.005和%.2f等)打印。
  • 顺便说一下,.1f 打印出.1f,缺少一个%
  • 在编译代码时启用警告,编译器会警告您缺少的 '%'。在带有 gcc 的 Linux 下,它打印了 warning: too many arguments for format [-Wformat-extra-args],显然该行有问题。

标签: c floating-point rounding


【解决方案1】:

与许多浮点问题一样,问题在于您的值isn't really 3.55

float f = 3.55f;
printf("%.10f\n", f);  // 3.5499999523

另见http://floating-point-gui.de/

所以除非你使用ceil(),否则这个值永远不会被四舍五入。

【讨论】:

    【解决方案2】:

    修改this answer to a related question by H2CO3 会产生所需的输出:

    float custom_round(float num, int prec)
    {
        float trunc = round(num * pow(10, prec+7));
        trunc = round(trunc/pow(10, 7));
        return trunc / pow(10, prec);
    }
    

    7 额外精度派生自 delta 值。我不认为它普遍适用,但是对于3.55f0.0499999f这两个数字,它指向的位置是第一个数字将向上舍入,而第二个数字将向下舍入。

    【讨论】:

      【解决方案3】:

      其他人指出示例中的十进制值没有精确的二进制等值。

      然后是增量:

      1. 有一个小数增量可能会弄乱您的四舍五入,因为将一个无法表示的数字添加到另一个数字不是最优的。
      2. 增量应基于二进制值,其数量级为 1/(2^23) 的 2^ 所显示数字的指数(单精度)或 1/(2^52)(双精度)。

      对于 16

      【讨论】:

        【解决方案4】:

        问:...函数将 3.55 转换为 3.6,将 0.0499999 转换为 0.0 ...?
        答:使用@Kninnug 答案,但保留小数点后一位。

        f = round(f * 10) / 10.0;
        

        它会给你3.5,因为数字f不是原来是3.55。没错,您使用文本“3.55”初始化了f,但C 和您的计算机无法准确表示该数字。 您的系统上没有 (float) 3.55。相反,f 的值约为 3.549999952...,因为它是最接近的选择。

        如果您仍然想要显示 f 舍入为 3.6 而不是 3.5,您需要将 f 向上微调一点。当它是 3.549999952... 时轻推,因此它的值 >= 3.55 并且当 f0.04999990016...(0.0499999 也不能完全表示)时,同样的轻推保持它 f

        我们可以增加的最小f 并看到变化是nextafterf(f, g)g 是您希望达到的值。

        3.549999952...   --> 3.550000190...
        0.04999990016... --> 0.04999990389...
        
        printf("%.1f\n", nextafterf(f, 2*f));
        // prints 3.6 when f is 3.549999952...
        // prints 0.0 when f is 0.04999990389...
        

        建议您查看@Oli Charlesworth 答案中的参考。

        【讨论】:

          【解决方案5】:

          这里的代码有效。我对代码进行了注释,以便您理解。

              #include <stdio.h>
              #include <stdlib.h>
          
          int main(int argc, char const *argv[])
          {
              float delta = 1e-7;
              float f = 3.55f;
          
              // Here we minus f (3.55) from the integer of f (3) so 3.55 - 3 = 0.55
              // Then we check whether the value is bigger than 0.5
              if( (f-(int)f) >= 0.5 ) { 
                      // If it is, then plus 0.01 to the answer. Thus making it 3.65
                  f = f + 0.01;
              } else {
                      // If its not, minus 0.01 from the answer.
                      // Assuming f is 3.44 this will make f 3.43
                  f = f - 0.01;
              }
          
              // Since you its to the first decimal place, the code above will output 
              // your desired result which is 3.6.
              printf("%.1f\n", f+delta);
              return 0;
          }
          

          【讨论】:

            【解决方案6】:

            我希望这会对你有所帮助。这是一个完整的四舍五入程序,但您只能使用该函数。

            #include <stdio.h>
            #include <math.h>
            #include <string.h>
            
            //function prototypes
            float roundon(float n,int to);
            
            void main(){
                //vars
                float num;
                int roundto;
                puts("Enter the decimal to be rounded");
                scanf("%f",&num);
            
                puts("Enter the number of decimal places to be rounded");
                scanf("%d",&roundto);
            
                float rounded= roundon(num,roundto);
                printf("The rounded value is %f\n",rounded);
            }
            
            //functions
            float roundon(float n, int to){
                //vars
                float rounded;
            
                int checker=(int) (n*pow(10,(to+1)))%10;
                int dec= (int) (n*pow(10,to));
                if(checker>=5){
                    dec++;
                }
            
                rounded= (float) dec/(pow(10,to));
                return (rounded);
            }
            

            【讨论】:

            • 输入要四舍五入的小数点 523.567 输入要四舍五入的小数位数 2 舍入值为 523.570007 (这是我使用上述程序的输出,但我不确定后面的 00007 来自哪里,但你可以解决这个问题。反正我用的是 Linux,你可能用过其他操作系统)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多