このコードは機能します (C# 3)
double d;
if(d == (double)(int)d) ...;
- これを行うより良い方法はありますか?
- 無関係な理由で、ダブルキャストを避けたいので; これ以外にどんな良い方法がありますか?(たとえ上手くいかなくても)
注:何人かの人々は、 == がしばしば浮動小数点の格下げに問題があるという (重要な) ポイントを指摘しました。この場合、0 から数百の範囲の値が期待され、それらは整数であると想定されます (非 int はエラーです)。
このコードは機能します (C# 3)
double d;
if(d == (double)(int)d) ...;
注:何人かの人々は、 == がしばしば浮動小数点の格下げに問題があるという (重要な) ポイントを指摘しました。この場合、0 から数百の範囲の値が期待され、それらは整数であると想定されます (非 int はエラーです)。
d == Math.Floor(d)
言い換えれば同じことをします。
注意: この種のことを行うときは、非常に注意する必要があることを認識していただければ幸いです。floats/doubles は非常に簡単に小さなエラーを蓄積し、明確な理由もなく正確な比較 (このようなもの) を失敗させます。
これはうまくいくと思います:
if (d % 1 == 0) {
//...
}
質問の C# 固有の部分にはお答えできませんが、浮動小数点数に関する一般的な問題が見落とされている可能性があることを指摘しておく必要があります。
一般に、float では整数性は明確に定義されていません。同じ理由で、float では同等性が適切に定義されていません。浮動小数点の計算には通常、丸め誤差と表現誤差の両方が含まれます。
たとえば、1.1 + 0.6 != 1.7.
ええ、それは浮動小数点数が機能する方法です。
ここで、1.1 + 0.6 - 1.7 == 2.2204460492503131e-16.
厳密に言えば、float で実行できる等値比較に最も近いのは、それらを選択した精度まで比較することです。
これで十分でない場合は、10 進数表現、組み込みの誤差範囲を持つ浮動小数点数表現、またはシンボリック計算を使用する必要があります。
double が別の計算の結果である場合、おそらく次のようなものが必要です。
d == Math.Floor(d + 0.00001);
そうすれば、わずかな丸め誤差があったとしても、一致します。
'x == floor(x)' などの単純なテストは、固定精度の FP 数に対して数学的に正しく動作することが保証されています。
すべての正当な固定精度 FP エンコーディングは個別の実数を表すため、すべての整数 x に対して、正確に一致する固定精度 FP エンコーディングは最大で 1 つ存在します。
したがって、そのような方法で表すことができるすべての整数 x について、必然的に x == floor(x) になります。これは、定義により floor(x) が y <= x および y が整数を表すような最大の FP 数 y を返すためです。したがって、floor(x) は x を返す必要があります。
変換するだけの場合、Mike F / Khoth の回答は良いですが、あなたの質問には完全には答えていません。実際にテストするつもりであり、それが実際に重要である場合は、誤差の範囲を含むものを実装することをお勧めします.
たとえば、お金を考えていて、偶数の金額をテストしたい場合は、次のように言うことができます (Khoth のパターンに従って):
if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)
つまり、値とその整数表現の差の絶対値を取り、それが小さいことを確認します。
そこに余分な(ダブル)は必要ありません。これは機能します:
if (d == (int)d) {
//...
}
Math.Truncate() を使用する
これにより、浮動小数点のドリフトを考慮して、探している精度 (プラスまたはマイナスの半ティック) を選択できます。比較も不可欠であり、これは素晴らしいことです。
static void Main(string[] args)
{
const int precision = 10000;
foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
{
if ((int) (d*precision + .5)%precision == 0)
{
Console.WriteLine("{0} is an int", d);
}
}
}
そして出力は
2 is an int
1.99999999 is an int
2.00000001 is an int
double の精度を処理するには...
Math.Abs(d - Math.Floor(d)) <= double.Epsilon
double.Epsilon より小さい値がゼロとして比較できない次のケースを考えてみましょう。
// number of possible rounds
const int rounds = 1;
// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;
// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));
// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);
// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));
これを使っていただけますか
bool IsInt(double x)
{
try
{
int y = Int16.Parse(x.ToString());
return true;
}
catch
{
return false;
}
}
このようなもの
double d = 4.0;
int i = 4;
bool equal = d.CompareTo(i) == 0; // true