9

公差やパーセンテージの違いではなく、小数点 (有効数字) の設定数を使用して 2 つの浮動小数点数を比較し、それらが等しいかどうかを判断する拡張メソッドを作成しています。float の比較に関する他の質問を見ると、複雑な実装が表示されます。私は単純化しすぎましたか、それともこれは有効ですか?

/// <summary>
/// Determines if the float value is equal to (==) the float parameter according to the defined precision.
/// </summary>
/// <param name="float1">The float1.</param>
/// <param name="float2">The float2.</param>
/// <param name="precision">The precision.  The number of digits after the decimal that will be considered when comparing.</param>
/// <returns></returns>
public static bool AlmostEquals(this float float1, float float2, int precision = 2)
{
    return (Math.Round(float1 - float2, precision) == 0);
}

注:公差ではなく、小数点以下の桁数での比較を探しています。1,000,000 を 1,000,001 に等しくしたくありません。

4

2 に答える 2

2

@infactの回答と、私が思いついた質問と回答の両方のコメントに基づいて

public static bool AlmostEquals(this float float1, float float2, int precision = 2) 
{ 
    float epsilon = Math.Pow(10.0, -precision) 
    return (Math.Abs(float1-float2) <= epsilon);   
} 

これには、任意の整数を受け入れるという利点があります。precision = -x を使用して 1.0 を超える精度を確認できます。ここで、x は確認する 10 の累乗です。

また、デフォルトの精度 = 3 にすることをお勧めします。これにより、この方法が財務に使用された場合、デフォルトで 10 分の 1 の精度が得られます。

于 2012-02-07T18:27:55.803 に答える
1

ユーザーが「設定された小数点数(有効数字)を使用して2つの浮動小数点数を比較する」ことを希望し、これは実際には関数があることを意味します

AlwaysEquals(14.3XXXXXXXX、14.3YYYYYYY、1)==すべての可能なXXXおよびYYYに対して真であり、最後のパラメーターは小数点以下の小数点以下の桁数です。

単純ですが残念な答えがあります:

この契約を履行するこの機能をプログラムすることはできません。多くの場合正しい結果が得られるものをプログラムすることは可能かもしれませんが、これがいつになるかを予測することはできないため、この関数は事実上無価値です。

ここで与えられた解は、AlmostEquals(0.06f、0.14f、1)= trueですが、0!=1ですでに壊れています。

なんで ?最初の理由は極端な感度です。例:0.0999999999....と0.100000... 1は、そもそも数字が異なりますが、違いはほとんど区別できず、ほぼ同じです。神話上の関数が何をするにしても、計算のわずかな違いさえ許すことはできません。

2つ目の理由は、実際に数値で計算したいということです。私はVC2008とC#を使用して、Math.pow関数の正しい値を出力しました。1つ目は精度パラメーター、2つ目は結果のfloatの16進値、3つ目は正確な10進値です。

1 3dcccccd 0.100000001490116119384765625

2 3c23d70a 0.00999999977648258209228515625

3 3a83126f 0.001000000047497451305389404296875

4 38d1b717 0.0000999999974737875163555145263671875

5 3727c5ac 0.00000999999974737875163555145263671875

6 358637bd 9.999999974752427078783512115478515625E-7

ご覧のとおり、シーケンス0.1、0.01、0.001などは、優れた近似値であるが、わずかに小さすぎるか大きすぎる数値を生成します。

指定された場所に正しい数字が必要であると強制した場合はどうなりますか?4ビットの16個のバイナリ値を列挙しましょう

0.0
0.0625
0.125
0.1875
0.25
0.3125
0.375
0.4375
0.5
0.5625
0.625
0.6875
0.75
0.8125
0.875
0.9375

小数点以下1桁だけで計算する場合は、10個の10進数に対して16個の異なる2進数で十分です。0.5はまったく同じですが、同じ10進数を適用すると、0.4には0.4375が必要であり、0.9には0.9375が必要であり、重大なエラーが発生します。

極端な感度の最初の条件に違反すると、そのような数値では合理的なことは何もできなくなります。数値の小数点以下の桁数に特定の値があることがわかっている場合は、最初に計算する必要はありません。

C#のドキュメントには、例も引用されています:http: //msdn.microsoft.com/en-us/library/75ks3aby.aspx

発信者へのメモ

10進値を浮動小数点数として表すか、浮動小数点値に対して算術演算を実行すると精度が低下するため、場合によっては、Round(Double、Int32)メソッドが中間値を最も近い偶数に丸めないように見えることがあります。桁の小数点以下の値。これを次の例に示します。ここでは、2.135が2.14ではなく2.13に丸められています。これは、メソッドが内部で値を10桁で乗算するために発生し、この場合の乗算演算では精度が低下します。

于 2012-02-09T13:45:59.850 に答える