圆形正值半到2位小数

时间:2014-08-03 12:59:06

标签: c number-formatting output-formatting

通常情况下,

可以很容易地舍入到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中是可行的,但仅适用于整数;

int a = (int)(b+0.5)

所以,我要求如何做同样的事情,在正值上用2位小数而不是Integer来实现我之前说的用于打印

3 个答案:

答案 0 :(得分:2)

目前尚不清楚你是否真的希望&#34; 围绕半场&#34;或者更确切地说&#34; 从零开始的一半 &#34;,这需要对负值进行不同的处理。

单精度二进制float精确到至少6个小数位,20为double,因此通过DBL_EPSILON(在float.h中定义)轻推FP值将导致向上舍入到 n.nn5 值的下一个第100个printf( "%.2lf", x )。不影响值 n.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

答案 1 :(得分:1)

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

OP的观察结果是,对于“圆形到均匀”或“从零开圆”,“中途”数字的舍入是误导性的。在100个“中途”数字中,如0.005,0.015,0.025,... 0.995,只有4个通常正好“中途”:0.125,0.375,0.625,0.875。这是因为浮点数格式使用base-2,而像2.565这样的数字无法准确表示。

相反,2.565等样本数与[{1}}的{​​{1}}值相近,假设为binary64。根据OP的要求,将该数字舍入到最接近的0.01应为2.56而不是2.57。

因此,只有0.125和0.625区域的数字完全中途并向下舍入而不是按照OP的要求向上舍入。建议接受并使用:

double

为了接近OP的目标,数字可能是A)测试结束时以0.125或0.625或B)略有增加。增幅最小的是

2.564999999999999947...

@Clifford找到了另一种微调方法。


[前回答将printf("%.2lf",variable); // This should be sufficient 四舍五入到最接近{0.01}的#include <math.h> printf("%.2f", nextafter(x, 2*x)); 倍数

典型的浮点使用类似binary64的格式,它使用base-2。 “舍入到最接近的数学0.01并且与0.0的关系”具有挑战性。

正如@Pascal Cuoq所提到的,像double这样的浮点数通常只接近double并且具有更精确的值,例如2.555 一半方式。

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

2.555
  

“round函数将其参数四舍五入到浮点数中最接近的整数值   格式,无论当前的舍入方向如何,都将中途的情况从零处舍入。“C11dr§7.12.9.6。

2.555000000000000159872...方法有两个问题:它可能在错误的方向上舍入为负数(OP未指定),而整数通常具有更小的范围(x = round(100.0*x)/100.0; ((int)(100 * (x + 0.005)) / 100.0)INT_MIN


仍有一些情况,例如当INT_MAX最终接近1.12时真的应该是double因为double x = atof("1.115");,因为1.11真的更接近{ {1}}而不是“中途”。

1.115

假设double,OP未指定负数舍入。

答案 2 :(得分:1)

以下是将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 %.2f\n", "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;
}