web-dev-qa-db-ja.com

C#で小数値を適切に比較する方法は?

私はC++のバックグラウンドから来ましたが、フロートを同等に正確に比較できないことを知っています。 C#の場合、10進数値、または一般的な浮動小数点値に同じポリシーが適用されると単純に仮定しました。

基本的に、2つの10進数値があり、それらが互いに等しくない場合、何らかのアクションを実行する必要があります。例えば。:

decimal value1, value2;
// Assume value1 and value2 are set somewhere to valid values.
if( value1 != value2 )
{
    // Do something
}

これが期待どおりに機能しない場合は、.00001などのようなエラーのマージンと同等の比較を行うソリューションを受け入れます。この問題の推奨される解決策は何ですか?

46
void.pointer

コードは期待どおりに機能します。 C#decimalsは、基数10の数値を非常に正確に表現するように最適化されているため、比較している場合(金額など)、すべて正常です。

Jon Skeetによる小数の精度に関する非常に明確な説明を次に示します。

。NETでの10進数、浮動小数点数、および倍数の違い?

29
fretje

私は似たようなことを調査していましたが、エラーのマージンではなく精度で、Floatの拡張機能を作成することになりました。ただし、これはどのタイプにも簡単に適用できます。一連の複雑な比較があり、これにより見やすくなりました。

/// <summary>
/// A set of extensions to allow the convenient comparison of float values based on a given precision.
/// </summary>
public static class FloatingPointExtensions
{
    /// <summary>
    /// Determines if the float value is less than or 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 LessThan(this float float1, float float2, int precision)
    {
        return (System.Math.Round(float1 - float2, precision) < 0);
    }

    /// <summary>
    /// Determines if the float value is less than or 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 LessThanOrEqualTo(this float float1, float float2, int precision)
    {
        return (System.Math.Round(float1 - float2, precision) <= 0);
    }

    /// <summary>
    /// Determines if the float value is greater than (>) 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 GreaterThan(this float float1, float float2, int precision)
    {
        return (System.Math.Round(float1 - float2, precision) > 0);
    }

    /// <summary>
    /// Determines if the float value is greater than or 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 GreaterThanOrEqualTo(this float float1, float float2, int precision)
    {
        return (System.Math.Round(float1 - float2, precision) >= 0);
    }

    /// <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)
    {
        return (System.Math.Round(float1 - float2, precision) == 0);
    } 
}
5
Kim

私は他の答えに同意しますが、1つの「本物の」サーバー側の小数がJSON /ブラウザから来るものと比較されるという問題に遭遇します(そしてある時点でフロートであったに違いありません)。

私はこのコードで小数点以下2桁までになりましたが、私の場合は十分に正確でした:

if (Decimal.Round(serverTotalPrice, 2) != Decimal.Round(request.TotalPrice, 2)) {
    throw new ArgumentException("The submitted Total Price is not valid");
}
4
Ekus

this が問題を解決すると思います。

基本的に、decimal.compareメソッドがあります。

編集:これはより良い方法かもしれません:

10進数で等しい

EDIT2:上記のように直接比較できる場合は、より効率的かもしれません。興味があるかもしれないので、これは残しておきます。

2
nycdan