比较浮点数作为字符串!我可以吗?这是有效的方法吗?

时间:2013-05-16 08:54:05

标签: c# floating-point

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

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

这种“做法”是否可以接受?还有更好的方法吗?怎么样?

P.S。我是c#和强类型语言的新手!所以,如果您有简短的解释,我很乐意阅读它!

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

的原因

4 个答案:

答案 0 :(得分: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.1001的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();
        }
    }
}

但是,以下内容可能就是您的答案

或者,您可以使用the decimal type代替浮点数,然后直接比较将起作用(针对此特定情况):

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");

答案 1 :(得分:3)

您举两个数字的例子

353.58
353.59

这些数字无法以二进制浮点格式精确表示。此外,值0.01无法以二进制浮点格式精确表示。请阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic

因此,例如,当您尝试将353.58表示为float时,没有float具有该值,并且您获得最接近的浮点值恰好为{{ 3}}

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

然后你可以写:

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

使用decimaldecimal.Parse()将数字的文字表示转换为decimal值。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

这不是一个很好的方法。没有必要将它与字符串进行比较,你不会通过这样做获得任何东西。将它与实际的浮点值进行比较。

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