6

通常、小数点以下 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桁を使用して上記と同じことを行う方法を求めて、以前に印刷について述べたことを達成します。

4

3 に答える 3

2

実際に「半分を切り上げる」か、「ゼロから半分を切り捨てる」かは明確ではありません。これには、負の値に対して異なる処理が必要です。

単精度バイナリfloatは、少なくとも小数点以下 6 桁まで正確であり、 の場合は 20 ですdouble。そのため、DBL_EPSILON (float.h で定義) によって FP 値を微調整すると、printf( "%.2lf", x )n.nn5によって次の 100 位に切り上げられます。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
于 2014-08-03T19:37:43.460 に答える
1

double以下は、 aを最も近いに丸める正確なコード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;
}
于 2014-08-03T23:51:27.380 に答える
1

[編集] OP は、印刷された値のみを小数点以下 2 桁に丸める必要があることを明確にしました。

「偶数への丸め」または「ゼロからの丸め」ごとに「途中で」数値を丸めるというOPの観察は誤解を招くものです。0.005、0.015、0.025、... 0.995 のような 100 個の「中途半端な」数値のうち、通常、正確に「中途半端」なのは 0.125、0.375、0.625、0.875 の 4 つだけです。これは、浮動小数点数の形式が基数 2 を使用し、2.565 のような数値を正確に表すことができないためです。

代わりに、次のようなサンプル番号は、 binary64を想定し2.565た最も近いdouble値に なります。その数値を 0.01 に最も近い値に丸めると、OP が要求する 2.57 ではなく 2.56 になるはずです。2.564999999999999947...

したがって、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[aを最も近いdouble0.01 の倍数に丸める以前の回答]

典型的な浮動小数点は、基数 2 を使用するbinary64のような形式を使用します。「最も近い数学的 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)アプローチには 2 つの問題があります。負の数の場合は間違った方向に丸められる可能性があり (OP では指定されていません)、通常、整数の範囲 ( INT_MININT_MAX)ははるかに小さくなりますdouble


double x = atof("1.115");1.12 の近くで終了する場合のような場合がまだいくつかあります1.11。これ1.115は、adoubleが実際には に近く、1.11「中途半端」ではないためです。

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

OP は、負の数の丸めを指定していませんy = -f(-x)

于 2014-08-03T18:22:40.607 に答える