How to properly compare decimal values in C#?

后端 未结 4 736
忘掉有多难
忘掉有多难 2020-12-16 09:23

I come from a background in C++, and I know that you cannot accurately compare floats for equality. For C#, I simply assumed the same policy applies to decimal values, or an

相关标签:
4条回答
  • 2020-12-16 09:35

    I agree with the other answers, but I run into a problem where one "authentic" server-side decimal gets compared with one coming from JSON/browser (and must have been a float at some point).

    I ended up with this code to round to 2 digits after the decimal point, which was precise enough in my case:

    if (Decimal.Round(serverTotalPrice, 2) != Decimal.Round(request.TotalPrice, 2)) {
        throw new ArgumentException("The submitted Total Price is not valid");
    }
    
    0 讨论(0)
  • 2020-12-16 09:40

    I was investigating something similar, but with a precision instead of a margin of error and ended up writing some extensions for Float. This can easily be adapted for any type though. I've got a complicated series of comparisons and this makes it nice and readable.

    /// <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);
        } 
    }
    
    0 讨论(0)
  • 2020-12-16 09:47

    I think this will solve your problem.

    Basically there is a decimal.compare method.

    EDIT: This may be the better method:

    Decimal.Equals

    EDIT2: If you can compare directly as suggested above, that may be more efficient. I will leave this as it may be of interest.

    0 讨论(0)
  • 2020-12-16 09:49

    Your code will work as expected. C# decimals are optimized to be very accurate at representing base 10 numbers, so if that's what you're comparing (money, ...), everything should be fine.

    Here's a very clear explanation about the accuracy of decimals by Jon Skeet:

    Difference between decimal, float and double in .NET?

    0 讨论(0)
提交回复
热议问题