如何正确比较C#中的十进制值?

voi*_*ter 49 c# floating-point comparison

我来自C++的背景,我知道你无法准确地比较浮点数是否相等.对于C#,我只是假设相同的策略适用于十进制值或一般的任何浮点值.

基本上,我有两个十进制值,如果它们彼此不相等,我需要执行一些操作.例如:

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

如果这不能按预期工作,我愿意接受一个与误差范围进行相等比较的解决方案,比如.00001或类似的东西.这个问题的推荐解决方案是什么?

fre*_*tje 32

您的代码将按预期工作.C#decimal被优化为非常准确地表示基数为10的数字,所以如果你正在比较(钱,...),一切都应该没问题.

以下是Jon Skeet关于小数精度的非常明确的解释:

.NET中的decimal,float和double之间的区别?

  • @Robert:在小数点位置"浮动"的意义上,小数是浮点数.小数不是"固定点"数字,例如,小数点前15位,后10位.十进制和双精度之间的差异是十进制是mx 10 ^ e形式的数字,而double是mx 2 ^ e形式的数字. (7认同)
  • 刚刚看到`0.0000!= 0.0`返回true。但是`!(0.000).Equals(0.0)`返回false。 (2认同)

nyc*_*dan 5

我想会解决你的问题。

基本上有一个decimal.compare方法。

编辑:这可能是更好的方法:

小数.等于

EDIT2:如果您可以按照上面的建议直接比较,那可能会更有效。我会留下这个,因为它可能很有趣。


Kim*_*Kim 5

我正在研究类似的东西,但精确而不是误差,最后为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);
    } 
}
Run Code Online (Sandbox Code Playgroud)


Eku*_*kus 5

我同意其他答案,但我遇到了一个问题,将一个“真实的”服务器端小数与来自 JSON/浏览器的小数进行比较(并且在某些时候一定是浮点数)。

我最终用这段代码四舍五入到小数点后的2 位数字,这在我的情况下足够精确:

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

  • 对此类任务使用 round 可能会导致问题,因为 1.116 将四舍五入为 1.12,而 1.113 将四舍五入为 1.11,因此根据您的代码,它们将不相等,您似乎希望它们认为相等。 (3认同)