4

編集:デバッグセッション中に間違いを犯したため、この質問をすることになりました。私が見た違いは、実際にはdoubleの印刷とdoubleの解析(strtod)にありました。スティーブンの答えは、この修正後も私の質問を非常によくカバーしているので、誰かに役立つ場合に備えて、質問はそのままにしておくと思います。

私がアクセスできるいくつかの(ほとんどの)Cコンパイルプラットフォームは、FPU丸めモードを考慮に入れていません。

  • 64ビット整数をdouble;に変換します。
  • 印刷double

ここでは非常にエキゾチックなものはありません。MacOSXLeopard、最近のさまざまなLinuxおよびBSDバリアント、Windows。

一方、Mac OS X Snow Leopardは、これら2つのことを行うときに、丸めモードを考慮に入れているようです。もちろん、異なる行動をとることは私に終わりがないことを苛立たせます。

2つのケースの典型的なスニペットは次のとおりです。

#if defined(__OpenBSD__) || defined(__NetBSD__) 
# include <ieeefp.h>
# define FE_UPWARD FP_RP
# define fesetround(RM) fpsetround(RM)
#else 
# include <fenv.h>
#endif

#include <float.h>
#include <math.h>

fesetround(FE_UPWARD);

...
double f;
long long b = 2000000001;
b = b*b;
f = b;

...
printf("%f\n", 0.1);

私の質問は次のとおりです。

  1. すべてのプラットフォームで動作を正規化するためにできる、醜くないことはありますか?丸めモードを考慮に入れているプラ​​ットフォームに、またはその逆を行わないように指示するための隠された設定はありますか?
  2. 動作の標準の1つですか?
  3. FPU丸めモードを使用しない場合、何が発生する可能性がありますか?ゼロに向かって丸めますか?最も近いものに丸めますか?選択肢は1つしかないことを教えてください:)

2.について標準では、整数に変換された浮動小数点数は常に切り捨てられる(ゼロに丸められる)と言われている場所を見つけましたが、整数->浮動小数点数の方向については何も見つかりませんでした。

4

1 に答える 1

4

丸めモードを設定していない場合は、IEEE-754のデフォルトモードである必要があります。これは最も近い値です。

整数から浮動小数点数への変換については、C標準は次のように述べています(§6.3.1.4)。

整数型の値が実際の浮動型に変換されるときに、変換される値が新しい型で正確に表現できる場合、それは変更されません。変換される値が表現できるが正確に表現できない値の範囲内にある場合、結果は、実装定義の方法で選択された、最も近い高い値または最も近い低い表現可能な値のいずれかになります。変換される値が表現可能な値の範囲外である場合、動作は定義されていません。

したがって、両方の動作はC標準に準拠しています。

C標準では(§F.5)、IEC60559浮動小数点形式と文字シーケンス間の変換はIEEE-754標準に従って正しく丸められるとされています。非IEC60559形式の場合、これが推奨されますが、必須ではありません。1985年のIEEE-754規格は次のように述べています(5.4節)。

表3で指定された範囲内にあるオペランドについては、セクション4で指定されているように、変換は正しく丸められます。それ以外の場合、最も近い値に丸める場合、変換された結果の誤差は、宛先の最下位桁で0.47単位を超えてはなりません。これは、指数のオーバーフロー/アンダーフローが発生しないという条件で、セクション4の丸め仕様によって発生します。有向丸めモードでは、エラーは正しい符号を持ち、最後に1.47単位を超えてはなりません。

セクション(4)が実際に述べているのは、操作は一般的な丸めモードに従って行われるということです。つまり、丸めモードを変更すると、IEEE-754は、float->string変換の結果もそれに応じて変更されるはずだと言っています。整数->浮動小数点変換についても同様です。

IEEE-754標準の2008年改訂版は次のように述べています(4.3節)。

rounding-direction属性は、不正確である可能性のあるすべての計算操作に影響します。不正確な数値浮動小数点の結果は、常に丸められていない結果と同じ符号になります。

両方の変換は、5節で計算操作として定義されているため、一般的な丸めモードに従って実行する必要があります。

ここでは、Snow Leopardの動作が正しいと主張します(一般的な丸めモードに従って結果が正しく丸められていると仮定します)。古い動作を強制したい場合はprintf、丸めモードを変更するコードでいつでも呼び出しをラップできますが、それは明らかに理想的ではないと思います。

%aまたは、 C99準拠のプラットフォームでフォーマット指定子(16進浮動小数点)を使用することもできます。この変換の結果は常に正確であるため、一般的な丸めモードの影響を受けることはありません。Windows Cライブラリがサポートしているとは思いませんが、%a必要に応じてBSDまたはglibcの実装を簡単に移植できます。

于 2010-04-07T20:54:44.420 に答える