How to properly compare decimal values in C#?
C#ComparisonFloating PointC# Problem Overview
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 any floating point value in general.
Basically, I have two decimal values and if they are NOT equal to each other, I need to perform some action. e.g.:
decimal value1, value2;
// Assume value1 and value2 are set somewhere to valid values.
if( value1 != value2 )
{
// Do something
}
If this doesn't work as expected, I'm willing to accept a solution that does an equality comparison with a margin of error, say like .00001 or something like that. What would be the recommended solution to this problem?
C# Solutions
Solution 1 - C#
Your code will work as expected. C# decimal
s 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:
Solution 2 - C#
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);
}
}
Solution 3 - C#
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");
}
Solution 4 - C#
I think this will solve your problem.
Basically there is a decimal.compare method.
EDIT: This may be the better method:
EDIT2: If you can compare directly as suggested above, that may be more efficient. I will leave this as it may be of interest.