Подтвердить что ты не робот

Как правильно сравнивать десятичные значения в С#?

Я исхожу из фона на С++, и я знаю, что вы не можете точно сравнивать float для равенства. Для С# я просто предположил, что одна и та же политика применяется к десятичным значениям или любому значению с плавающей запятой в целом.

В принципе, у меня есть два десятичных значения, и если они НЕ равны друг другу, мне нужно выполнить какое-то действие. например:.

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

Если это не работает должным образом, я готов принять решение, которое сравнивает равенство с пределом ошибки, например, как .00001 или что-то в этом роде. Каким будет рекомендуемое решение этой проблемы?

4b9b3361

Ответ 1

Ваш код будет работать должным образом. С# decimal оптимизированы так, чтобы быть очень точными при отображении базовых 10 чисел, поэтому, если это то, что вы сравниваете (деньги,...), все должно быть хорошо.

Здесь очень четкое объяснение точности десятичных знаков Джона Скита:

Разница между десятичной, плавающей и двойной в .NET?

Ответ 2

Я изучал что-то подобное, но с точностью, а не с ошибкой, и в итоге написал некоторые расширения для 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);
    } 
}

Ответ 3

Я думаю, this решит вашу проблему.

В принципе существует метод decimal.compare.

EDIT: это может быть лучший метод:

Decimal.Equals

EDIT2: Если вы можете сравнить напрямую, как было предложено выше, это может быть более эффективным. Я оставлю это, поскольку это может представлять интерес.

Ответ 4

Я согласен с другими ответами, но у меня возникает проблема, когда один "аутентичный" дескриптор на стороне сервера сравнивается с одним из JSON/браузером (и должен был быть плавающим в какой-то момент).

Я закончил с этим кодом округлением до 2 цифр после десятичной точки, что было достаточно точным в моем случае:

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