3

为了检查两个浮点数之间的差异是否为 0.01,我这样做

if ((float1 - float.Parse(someFloatAsStringFromXML).ToString(), System.Globalization.CultureInfo.InvariantCulture)).ToString() == "0,01000977")

这种“方法”可以接受吗?有没有更好的办法?如何?

ps 我对 c# 和强类型语言非常陌生!所以,如果你有更多的简短解释,我很乐意阅读它!

我忘了提,那个数字是“353.58”和“353.59”。我将它们作为带有点“。”的字符串。不是 "," 这就是我使用 float.Parse 的原因

4

4 回答 4

5

首先,您应该始终将数字作为其基础类型(浮点数、双精度、十进制)进行比较,而不是作为字符串进行比较。

现在,您可能认为可以这样比较:

float floatFromXml = float.Parse(someFloatAsStringFromXML);

if (Math.Abs(float1 - floatFromXml) == 0.01)

我的示例如下:

首先,计算两个值之间的差:

float1 - floatFromXml

然后取它的绝对值(只是去掉减号)

Math.Abs(float1 - floatFromXml)

然后查看该值是否等于 0.01:

if (Math.Abs(float1 - floatFromXml) == 0.01)

如果你不想忽略这个标志,你就不会这样做Math.Abs()

if ((float1 - floatFromXml) == 0.01)

但这不适用于您的示例,因为舍入错误!

因为您使用的是浮点数(这也适用于双精度数),所以您将获得舍入误差,这使得将差异与 0.01 进行比较是不可能的。它将更像 0.01000001 或其他一些稍微错误的值。

要解决这个问题,您必须将实际差异与目标差异进行比较,如果差异很小,您就说“可以”。

在以下代码中,target是您正在寻找的目标差异。在你的情况下,它是0.01.

然后epsilontarget可能出错的最小量。在这个例子中,它是0.00001

我们所说的是“如果两个数字之间的差异在 0.1 的 0.00001 以内,那么我们将其视为匹配 0.1 的差异”。

所以代码计算两个数字之间的实际差异difference,然后它会看到这个差异有多远,0.01如果它在0.00001它里面打印“YAY”。

using System;

namespace Demo
{
    class Program
    {
        void Run()
        {
            float f1 = 353.58f;
            float f2 = 353.59f;

            if (Math.Abs(f1 - f2) == 0.01f)
                Console.WriteLine("[A] YAY");
            else
                Console.WriteLine("[A] Oh dear"); // This gets printed.

            float target = 0.01f;
            float difference = Math.Abs(f2 - f1);
            float epsilon = 0.00001f; // Any difference smaller than this is ok.

            float differenceFromTarget = Math.Abs(difference - target);

            if (differenceFromTarget < epsilon)
                Console.WriteLine("[B] YAY"); // This gets printed.
            else
                Console.WriteLine("[B] Oh dear"); 
        }

        static void Main()
        {
            new Program().Run();
        }
    }
}

但是,以下可能是您的答案

或者,您可以使用类型decimal不是浮点数,然后直接比较将起作用(对于这种特殊情况):

decimal d1 = 353.58m;
decimal d2 = 353.59m;

if (Math.Abs(d1 - d2) == 0.01m)
    Console.WriteLine("YAY"); // This gets printed.
else
    Console.WriteLine("Oh dear");
于 2013-05-16T08:57:28.763 回答
3

你举一个你的两个数字的例子

353.58
353.59

这些数字不能以二进制浮点格式精确表示。此外,该值0.01不能以二进制浮点格式精确表示。请阅读每个计算机科学家应该了解的关于浮点运算的知识

因此,例如,当您尝试表示353.58为 afloat时,该值不存在float,并且您得到最接近的浮点值,恰好是353.579986572265625

在我看来,您使用错误的数据类型来表示这些值。您需要使用十进制格式。这将允许您准确地表示这些值。在 C# 中,您使用decimal类型。

然后你可以写:

decimal value1 = 353.58m;
decimal value2 = 353.59m;
Debug.Assert(Math.Abs(value2-value1) == 0.01m);

使用decimal.Parse()decimal.TryParse()将数字的文本表示形式转换为decimal值。

于 2013-05-16T09:22:24.423 回答
0

直接回答你的问题,你能做到吗?是的。这是一种有效的方法吗?几乎可以肯定不是。

如果您提供更多上下文,您将获得更详细的答案。

于 2013-05-16T08:57:42.523 回答
0

这不是一个好方法。无需将其与字符串进行比较,并且这样做不会获得任何收益。将其与实际的浮点值进行比较。

您的方法立即可见的问题是它不安全。在英国,我们使用.而不是,作为小数点 - 所以结果.ToString()根本不匹配。但除此之外,在没有充分理由的情况下这样做是一种不好的做法。

于 2013-05-16T08:57:46.760 回答