比较两位小数

Comparing two decimals

我想在 C# 中比较两位小数,但有一些误差。谁能指出以下代码的问题。请注意,我对小数点后 6 位感兴趣,之后我可以忽略这些值。

var valOne = decimal.Round(valueOne, 6);
var valTwo = decimal.Round(valueTwo, 6);
var difference = Math.Abs(valOne - valTwo);
if (difference > 0.0000001m) {
   Console.WriteLine("Values are different");
}
else {
    Console.WriteLine("Values are equal");
}

或者有没有更好的方法

修正错别字 "var valTwo = decimal.Roung(valueTwo, 6);" 应该是 decimal.Round(....

您还可以使用 Decimal.Equals(dec1, dec2) 或 Decimal.Compare(dec1, dec2)

来比较十进制

你可以做一个函数,做这样的事情

public static bool Check(decimal first, decimal second, decimal margin) 
{ 
    return Math.Abs(first - second) <= margin; 
}

它会 return 真或假取决于值是否更小或相等

如果您将值四舍五入到小数点后 6 位,那么您的 epsilon 值太小了。两个值可以相差的最小量是 0.000001。

例如:

var valOne = Decimal.Round(1.1234560M, 6);    // Gives 1.123456
var valTwo = Decimal.Round(1.1234569M, 6);    // Gives 1.123457

if (Math.Abs(valOne - valTwo) >= 0.000001M)
{
    Console.WriteLine("Values differ");
}
else
{
    Console.WriteLine("Values are the same");
}

我想如果我不使用 Round 那么这个解决方案就可以了。

var valOne = 1.1234560M; // Decimal.Round(1.1234560M, 6);  Don't round.
var valTwo = 1.1234569M; // Decimal.Round(1.1234569M, 6);  Don't round

if (Math.Abs(valOne - valTwo) >= 0.000001M) // Six digits after decimal in epsilon
{
    Console.WriteLine("Values differ");
}
else
{
    Console.WriteLine("Values are the same");
}

如上所述,对于六位小数,两位小数可以相差的最小值为 0.000001M。小于此的任何内容都可以安全地忽略。我认为这个解决方案很好,但如果有人认为我遗漏了什么,我感谢你的帮助。

谢谢大家

以下对我有用:

var valueOne = 1.1234563M;
var valueTwo = 1.1234567M;

var diff = Math.Abs(valueOne - valueTwo);
//Console.WriteLine(diff);

if(diff > 0.0000003M)
{
    Console.WriteLine("diff");
}
else
{
    Console.WriteLine("equal");
}

以上会显示"diff"。

如果改成var valueOne = 1.1234565M;,差值会小于阈值,所以会显示"equal"。

然后你可以RoundTruncate,这取决于你的需要。

编辑: @tangokhi 刚刚注意到你的回答!你是对的..忽略我的回复。

此答案基于此处投票最高的答案:Floating point comparison functions for C#

here 所示,存在排除直接比较的边缘情况。基本上是因为小数可能相等,但实际上代码并不认为是相等的,即

float a = 0.15 + 0.15
float b = 0.1 + 0.2
if (a == b) { ... } // can be false!
if (a >= b) { ... } // can also be false!

您必须指定要比较数字的接近程度。 link 给出的答案作为 "Epsilon",但他们没有详细说明那是位值、范围还是给定数字的增量。

下面函数中的"Epsilon"将比较数字之间给定程度的差异。例如,如果您想使用上面的示例并使其恢复为真,您需要在 0.1 以内进行比较,而不是 0.01,就像在比较 0.30 和 0.3 时默认情况下所做的那样。

    public static bool nearlyEqual(double a, double b, double epsilon)
    {
        double absA = Math.Abs(a);
        double absB = Math.Abs(b);
        double diff = Math.Abs(a - b);

        if (a == b)
        { 
            // shortcut, handles infinities
            return true;
        }
        else if (a == 0 || b == 0 || diff < Double.Epsilon)
        {
            // a or b is zero or both are extremely close to it
            // relative error is less meaningful here
            return diff < epsilon;
        }
        else
        { 
            // use relative error
            return diff / (absA + absB) < epsilon;
        }
    }

假设您有一个包含项目 ID 和浮点十进制(双精度)数字的项目字典,就像一堆纬度...

 Dictionary<int, double> cityLatPoints = new Dictionary<int, double>();

并且您想知道某个纬度是否在其中一个点附近...您可以这样做:

double epsilon = 0.000005;
List<int> possLatCityIds = new List<int>();  // stores your matching IDs for later
double dblLat = 39.59833333;  // hard-coded value here, but could come from anywhere

// Possible Latitudes
foreach (KeyValuePair<int, double> kvp in cityLatPoints)
{
    if (nearlyEqual(kvp.Value, dblLat, epsilon))
    {
        //Values are the same or similar
        possLatCityIds.Add(kvp.Key);  // ID gets added to the list
    }
}

对于给定的示例,它看起来像这样:

decimal valOne = decimal.Round(valueOne, 6);
decimal valTwo = decimal.Round(valueTwo, 6);
double dblOne = Convert.ToDouble(valOne);
double dblTwo = Convert.ToDouble(valTwo);
double epsilon = 0.0000001;

if (nearlyEqual(dblOne, dblTwo, epsilon))
{
    Console.WriteLine("Values are equal");
}
else
{
    Console.WriteLine("Values are different");
}

此方法用于比较两个指定的 Decimal 值。 语法:public static int Compare (decimal a1, decimal a2);

参数: a1:This 参数指定要比较的第一个值。 a2:This 参数指定要比较的第二个值