在C中,将正数值的一半四舍五入到小数点后2位



一般来说,

很容易四舍五入到小数点后两位
printf("%.2lf",<variable>);
但是,舍入系统通常会舍入到最接近偶数的。例如,
2.554 -> 2.55
2.555 -> 2.56
2.565 -> 2.56
2.566 -> 2.57

我想要达到的是

2.555 -> 2.56
2.565 -> 2.57

实际上,四舍五入在C中是可行的,但只适用于Integer;

int a = (int)(b+0.5)

所以,我问的是如何做同样的事情与上面的2位小数的正值,而不是整数,以实现我之前说的打印

不清楚您是否真的想要"舍入一半",还是"舍入一半零",这需要对负值进行不同的处理。

单精度二进制float至少精确到小数点后6位,double精确到20位,因此通过DBL_EPSILON(在float.h中定义)推动FP值将导致printf( "%.2lf", x )n进行四舍五入到下一个100位。nn5 的值。不影响非值的显示值。nn5

double x2  = x * (1 + DBL_EPSILON) ; // round half-away from zero
printf( "%.2lf", x2 ) ;

对于不同的舍入行为:

double x2  = x * (1 - DBL_EPSILON) ;  // round half-toward zero
double x2  = x + DBL_EPSILON ;        // round half-up
double x2  = x - DBL_EPSILON ;        // round half-down

以下是将double四舍五入到最接近的0.01 double的精确代码。

代码的功能与x = round(100.0*x)/100.0;类似,除了它处理了使用操作以确保按100.0精确地完成缩放而不损失精度。

这可能比OP感兴趣的代码更多,但它确实工作。

它适用于整个double范围-DBL_MAXDBL_MAX。(仍然应该做更多的单元测试)。
它依赖于FLT_RADIX == 2,这是常见的。

#include <float.h>
#include <math.h>
void r100_best(const char *s) {
  double x;
  sscanf(s, "%lf", &x);
  // Break x into whole number and fractional parts.  
  // Code only needs to round the fractional part.  
  // This preserves the entire `double` range.
  double xi, xf;
  xf = modf(x, &xi);
  // Multiply the fractional part by N (256). 
  // Break into whole and fractional parts.
  // This provides the needed extended precision.
  // N should be >= 100 and a power of 2.
  // The multiplication by a power of 2 will not introduce any rounding.
  double xfi, xff;
  xff = modf(xf * 256, &xfi);
  // Multiply both parts by 100.  
  // *100 incurs 7 more bits of precision of which the preceding code
  //   insures the 8 LSbit of xfi, xff are zero.
  int xfi100, xff100;
  xfi100 = (int) (xfi * 100.0);
  xff100 = (int) (xff * 100.0); // Cast here will truncate (towards 0)
  // sum the 2 parts.  
  // sum is the exact truncate-toward-0 version of xf*256*100
  int sum = xfi100 + xff100;
  // add in half N
  if (sum < 0)
    sum -= 128;
  else
    sum += 128;
  xf = sum / 256;
  xf /= 100;
  double y = xi + xf;
  printf("%6s %25.22f ", "x", x);
  printf("%6s %25.22f %.2fn", "y", y, y);
}
int main(void) {
  r100_best("1.105");
  r100_best("1.115");
  r100_best("1.125");
  r100_best("1.135");
  r100_best("1.145");
  r100_best("1.155");
  r100_best("1.165");
  return 0;
}

[Edit] OP澄清,只有打印的值需要四舍五入到小数点后两位。

OP观察到每"四舍五入到偶数"或"四舍五入到零"的数字"一半"是误导性的。在100个"半途"数字中,比如0.005、0.015、0.025……0.995,只有4个典型的正好"一半":0.125,0.375,0.625,0.875。这是因为浮点数格式使用基数2,而像2.565这样的数字不能精确表示。

相反,假设binary64, 2.565等样本数具有与2.564999999999999947...最接近的double值。该数字四舍五入到最接近0.01的值应该是2.56,而不是op期望的2.57。

因此,只有以0.125和0.625结尾的数字正好位于的中间位置,并按op的要求向下四舍五入,而不是向上。建议接受并使用:

printf("%.2lf",variable);  // This should be sufficient

为了接近OP的目标,可以A)测试以0.125或0.625结尾的数字,或者B)稍微增加。最小的增长是

#include <math.h>
printf("%.2f", nextafter(x, 2*x));

另一个轻推方法是@Clifford。


[将double舍入到最接近于0.01的double倍数的前一个答案]

典型的浮点数使用像binary64这样的以2为基数的格式。"四舍五入到最接近的数学0.01,并远离0.0"是具有挑战性的。

正如@Pascal Cuoq提到的,像2.555这样的浮点数通常只接近2.555,并且有一个更精确的值,如2.555000000000000159872...,它是而不是的一半。

@BLUEPIXY的解决方案是最好的和实用的。

x = round(100.0*x)/100.0;

"舍入函数将其实参舍入到最接近的浮点整数值格式,舍入一半的情况下,远离零,不管当前的舍入方向。C11dr§7.12.9.6 .

((int)(100 * (x + 0.005)) / 100.0)方法有两个问题:它可能在错误的方向上对负数进行舍入(OP没有指定),并且整数通常具有比double小得多的范围(INT_MININT_MAX)。


仍然有一些情况,比如当double x = atof("1.115");最终接近1.12时,它实际上应该是1.11,因为1.115作为double实际上更接近1.11,而不是"中间"。

string   x                         rounded x 
1.115 1.1149999999999999911182e+00 1.1200000000000001065814e+00

OP没有指定负数的舍入,假设y = -f(-x)

相关内容

  • 没有找到相关文章

最新更新