11

C 標準ライブラリは、C99 のroundlround、およびllround関数ファミリを提供します。ただし、これらの関数は IEEE-754 に準拠していません。これは、IEEE で義務付けられている 2 分の 1 から偶数への「バンカーの丸め」を実装していないためです。半端から偶数への丸めでは、小数部分が正確に 0.5 の場合、結果を最も近い偶数値に丸める必要があります。cppreference.comに記載されているように、代わりに C99 標準ではゼロから半分離れていることが義務付けられています。

1-3) arg に最も近い整数値 (浮動小数点形式) を計算し、現在の丸めモードに関係なく、ゼロから離れて途中で丸めます。

C で丸めを実装する通常のアドホックな方法は、厳密な IEEE-754 数学では正しくない(int)(x + 0.5f)にもかかわらず、通常はコンパイラによって正しい命令に変換される式です。ただし、これは移植可能な仮定ではありません。cvtss2si

半分から偶数のセマンティクスで浮動小数点値を丸める関数を実装するにはどうすればよいですか? 可能であれば、関数は非 IEEE 浮動小数点型で動作できるように、言語と標準ライブラリのセマンティックのみに依存する必要があります。これが不可能な場合は、IEEE-754 ビット表現で定義された回答も受け入れられます。<limits.h>またはの観点から定数を特徴付けてください<limits>

4

6 に答える 6

6

数値 x を四捨五入します。x と四捨五入 (x) の差が正確に +0.5 または -0.5 で、四捨五入 (x) が奇数の場合、四捨五入 (x) は間違った方向に丸められているため、バツ。

于 2015-09-23T18:13:27.863 に答える
6

remainder(double x, 1.0)C 標準ライブラリから使用します。これは、現在の丸めモードとは無関係です。

剰余関数は、 IEC 60559で要求される剰余 x REM y を計算します。

remainder()OPの偶数要件への結びつきを満たしているため、ここで役立ちます。


double round_to_nearest_ties_to_even(double x) {
  x -= remainder(x, 1.0);
  return x;
}

テストコード

void rtest(double x) {
  double round_half_to_even = round_to_nearest_ties_to_even(x);
  printf("x:%25.17le   z:%25.17le \n", x, round_half_to_even);
}

void rtest3(double x) {
  rtest(nextafter(x, -1.0/0.0));
  rtest(x);
  rtest(nextafter(x, +1.0/0.0));
}

int main(void) {
  rtest3(-DBL_MAX);
  rtest3(-2.0);
  rtest3(-1.5);
  rtest3(-1.0);
  rtest3(-0.5);
  rtest(nextafter(-0.0, -DBL_MAX));
  rtest(-0.0);
  rtest(0.0);
  rtest(nextafter(0.0, +DBL_MAX));
  rtest3(0.5);
  rtest3(1.0);
  rtest3(1.5);
  rtest3(2.0);
  rtest3(DBL_MAX);
  rtest3(0.0/0.0);
  return 0;
}

出力

x:                     -inf   z:                     -inf 
x:-1.79769313486231571e+308   z:-1.79769313486231571e+308 
x:-1.79769313486231551e+308   z:-1.79769313486231551e+308 
x: -2.00000000000000044e+00   z: -2.00000000000000000e+00 
x: -2.00000000000000000e+00   z: -2.00000000000000000e+00 
x: -1.99999999999999978e+00   z: -2.00000000000000000e+00 
x: -1.50000000000000022e+00   z: -2.00000000000000000e+00 
x: -1.50000000000000000e+00   z: -2.00000000000000000e+00 tie to even
x: -1.49999999999999978e+00   z: -1.00000000000000000e+00 
x: -1.00000000000000022e+00   z: -1.00000000000000000e+00 
x: -1.00000000000000000e+00   z: -1.00000000000000000e+00 
x: -9.99999999999999889e-01   z: -1.00000000000000000e+00 
x: -5.00000000000000111e-01   z: -1.00000000000000000e+00 
x: -5.00000000000000000e-01   z:  0.00000000000000000e+00 tie to even 
x: -4.99999999999999944e-01   z:  0.00000000000000000e+00 
x:-4.94065645841246544e-324   z:  0.00000000000000000e+00 
x: -0.00000000000000000e+00   z:  0.00000000000000000e+00 
x:  0.00000000000000000e+00   z:  0.00000000000000000e+00 
x: 4.94065645841246544e-324   z:  0.00000000000000000e+00 
x:  4.99999999999999944e-01   z:  0.00000000000000000e+00 
x:  5.00000000000000000e-01   z:  0.00000000000000000e+00 tie to even 
x:  5.00000000000000111e-01   z:  1.00000000000000000e+00 
x:  9.99999999999999889e-01   z:  1.00000000000000000e+00 
x:  1.00000000000000000e+00   z:  1.00000000000000000e+00 
x:  1.00000000000000022e+00   z:  1.00000000000000000e+00 
x:  1.49999999999999978e+00   z:  1.00000000000000000e+00 
x:  1.50000000000000000e+00   z:  2.00000000000000000e+00 tie to even 
x:  1.50000000000000022e+00   z:  2.00000000000000000e+00 
x:  1.99999999999999978e+00   z:  2.00000000000000000e+00 
x:  2.00000000000000000e+00   z:  2.00000000000000000e+00 
x:  2.00000000000000044e+00   z:  2.00000000000000000e+00 
x: 1.79769313486231551e+308   z: 1.79769313486231551e+308 
x: 1.79769313486231571e+308   z: 1.79769313486231571e+308 
x:                      inf   z:                      inf 
x:                      nan   z:                      nan 
x:                      nan   z:                      nan 
x:                      nan   z:                      nan 
于 2015-09-23T23:32:13.450 に答える
2

データ型は、8388608.0f から 16777216.0f の範囲内のfloatすべての整数を表すことができますが、小数は表すことができません。8388607.5ffloatより大きい数値はすべて整数であり、丸めは必要ありません。それより小さい非負数に 8388608.0f を追加するfloatと、現在の丸めモード (通常は半分を偶数に丸める) に従って丸められる整数が得られます。8388608.0f を減算すると、元の値が適切に丸められたバージョンが得られます (適切な範囲内にあると仮定します)。

したがって、次のようなことができるはずです。

float round(float f)
{
  if (!(f > -8388608.0f && f < 8388608.0f)) // Return true for NaN
    return f;
  else if (f > 0)
    return (float)(f+8388608.0f)-8388608.0f;
  else
    return (float)(f-8388608.0f)+8388608.0f;
}

他の「整数への丸め」機能を使用する必要なく、加算の自然な丸め動作を利用できます。

于 2015-09-25T22:44:41.973 に答える