如何在C中四舍五入浮点值(如37.777779)到小数点后两位(37.78)?


当前回答

没有办法将一个浮点数四舍五入为另一个浮点数,因为四舍五入的浮点数可能不可表示(浮点数的限制)。例如,假设你将37.777779四舍五入为37.78,但最接近的数字是37.781。

然而,你可以使用格式化字符串函数来“舍入”浮点数。

其他回答

假设你谈论的是打印的值,那么Andrew Coleson和AraK的答案是正确的:

printf("%.2f", 37.777779);

但请注意,如果你的目标是将数字四舍五入到37.78以供内部使用(例如与另一个值进行比较),那么这不是一个好主意,因为浮点数的工作方式:你通常不想对浮点数进行相等比较,而是使用一个目标值+/-一个sigma值。或者将数字编码为具有已知精度的字符串,并进行比较。

请参阅Greg Hewgill对相关问题的回答中的链接,其中还涵盖了为什么不应该使用浮点数进行财务计算。

此函数接受数字和精度,并返回四舍五入后的数字

float roundoff(float num,int precision)
{
      int temp=(int )(num*pow(10,precision));
      int num1=num*pow(10,precision+1);
      temp*=10;
      temp+=5;
      if(num1>=temp)
              num1+=10;
      num1/=10;
      num1*=10;
      num=num1/pow(10,precision+1);
      return num;
}

它通过左移浮点数并检查大于5的条件将浮点数转换为int。

使用%。printf中的2f。它只打印2个小数点。

例子:

printf("%.2f", 37.777779);

输出:

37.77

Let me first attempt to justify my reason for adding yet another answer to this question. In an ideal world, rounding is not really a big deal. However, in real systems, you may need to contend with several issues that can result in rounding that may not be what you expect. For example, you may be performing financial calculations where final results are rounded and displayed to users as 2 decimal places; these same values are stored with fixed precision in a database that may include more than 2 decimal places (for various reasons; there is no optimal number of places to keep...depends on specific situations each system must support, e.g. tiny items whose prices are fractions of a penny per unit); and, floating point computations performed on values where the results are plus/minus epsilon. I have been confronting these issues and evolving my own strategy over the years. I won't claim that I have faced every scenario or have the best answer, but below is an example of my approach so far that overcomes these issues:

假设小数点后6位被认为是浮点数/双精度数计算的足够精度(这是对特定应用的任意决定),使用以下舍入函数/方法:

double Round(double x, int p)
{
    if (x != 0.0) {
        return ((floor((fabs(x)*pow(double(10.0),p))+0.5))/pow(double(10.0),p))*(x/fabs(x));
    } else {
        return 0.0;
    }
}

四舍五入到小数点后2位的结果可以这样表示:

double val;
// ...perform calculations on val
String(Round(Round(Round(val,8),6),2));

对于val = 6.825,结果是预期的6.83。

对于val = 6.824999,结果为6.82。这里假设计算结果正好是6.824999,小数点后第7位为零。

对于val = 6.8249999,结果为6.83。在这种情况下,小数点后第7位是9,使Round(val,6)函数给出预期的结果。在这种情况下,后面可能有任意数量的9。

对于val = 6.824999499999,结果为6.83。作为第一步,舍入到小数点后第8位,即Round(val,8),解决了一个棘手的情况,即计算的浮点结果计算为6.8249995,但在内部表示为6.824999499999....

最后,问题中的例子…Val = 37.777779的结果是37.78。

这种方法可以进一步概括为:

double val;
// ...perform calculations on val
String(Round(Round(Round(val,N+2),N),2));

其中N是浮点数/双精度数上所有中间计算所要维持的精度。这也适用于负值。我不知道这种方法在数学上是否适用于所有可能性。

使用float roundf(float x)。

舍入函数将其参数舍入为浮点格式中最接近的整数值,无论当前舍入方向如何,舍入距离为零的中间情况。C11dr§7.12.9.5

#include <math.h>
float y = roundf(x * 100.0f) / 100.0f; 

根据你的浮点数实现,看起来是一半的数字并不是。因为浮点数通常是面向2进制的。此外,在所有“中途”情况下,精确舍入到最接近0.01是最具挑战性的。

void r100(const char *s) {
  float x, y;
  sscanf(s, "%f", &x);
  y = round(x*100.0)/100.0;
  printf("%6s %.12e %.12e\n", s, x, y);
}

int main(void) {
  r100("1.115");
  r100("1.125");
  r100("1.135");
  return 0;
}

 1.115 1.115000009537e+00 1.120000004768e+00  
 1.125 1.125000000000e+00 1.129999995232e+00
 1.135 1.134999990463e+00 1.139999985695e+00

虽然“1.115”是介于1.11和1.12之间的“中间值”,但当转换为float时,其值为1.115000009537…并且不再是“半程”,而是更接近1.12,并四舍五入到最接近的浮动1.120000004768…

“1.125”是介于1.12和1.13之间的“中间值”,当转换为float时,值正好是1.125,是“中间值”。由于与偶数规则的关系,它四舍五入到1.13,并四舍五入到最接近的浮点数1.129999995232…

虽然“1.135”是介于1.13和1.14之间的“中间值”,但当转换为float时,其值为1.134999990463…并且不再是“半途”,而是更接近1.13,并舍入到最接近的浮动1.129999995232…

如果使用代码

y = roundf(x*100.0f)/100.0f;

虽然“1.135”是介于1.13和1.14之间的“中间值”,但当转换为float时,其值为1.134999990463…并且不再是“半路”,而是更接近1.13,但错误地舍入到浮动1.139999985695…由于浮点数和双精度数的精度更有限。这个不正确的值可能被视为正确的,这取决于编码目标。