C# 在c语言中测试实际浮点等式的理想方法#

C# 在c语言中测试实际浮点等式的理想方法#,c#,floating-point,C#,Floating Point,所以我很长一段时间以来都明白,浮点等式在任何编程语言中都不是完美的。但直到最近,在发现了一个与这个问题相关的bug之后,我才意识到这些情况有多奇怪 以下是一些例子: 我从一个低层次上理解了为什么会发生这种情况。但在我的应用程序中(我敢打赌在大多数应用程序中),出于实际目的,我们希望上述四个示例都是true 我发现的大多数解决方案都是取两个变量的绝对值,然后加上一个精度因子。例如: var isEqual = Math.Abs(a - b) < 1e-15; 但我注意到这方面存在一

所以我很长一段时间以来都明白,浮点等式在任何编程语言中都不是完美的。但直到最近,在发现了一个与这个问题相关的bug之后,我才意识到这些情况有多奇怪

以下是一些例子:

我从一个低层次上理解了为什么会发生这种情况。但在我的应用程序中(我敢打赌在大多数应用程序中),出于实际目的,我们希望上述四个示例都是
true

我发现的大多数解决方案都是取两个变量的绝对值,然后加上一个精度因子。例如:

var isEqual = Math.Abs(a - b) < 1e-15;
但我注意到这方面存在一些问题:

  • 在比较
    double
    float
    类型时,上述方法不一定有效
  • 它可能很难理解,尤其是作为更大表达式的一部分
所以我的问题是,确定浮点数实际相等性的理想方法是什么?我目前正在使用C#,但也对其他通用编程语言的答案感兴趣

我对理想的定义如下:

  • 工作100%的时间
  • 易于阅读/理解
  • 高性能

谢谢

如果有符合您标准的比较

  • 工作100%的时间
  • 易于阅读/理解
  • 高性能
然后,您最喜欢的编程语言已经在浮点类型上定义了比较运算符

但实际上,根据存储的数字的含义,“正确”的做法大相径庭浮点等式没有一刀切的放松

你必须考虑你拥有的数据,它的准确性,测量误差,量化误差,计算中的舍入误差,以及你用它做的决定。试图将这种想法委托给制造通用工具的人注定要失败

即使使用深层域知识定义“足够平等”,也会遇到很多陷阱,例如,您可能会发现:



1“may”的意思是,这种情况比“理想”的浮点比较更常见。

如果有符合您标准的比较

  • 工作100%的时间
  • 易于阅读/理解
  • 高性能
然后,您最喜欢的编程语言已经在浮点类型上定义了比较运算符

但实际上,根据存储的数字的含义,“正确”的做法大相径庭浮点等式没有一刀切的放松

你必须考虑你拥有的数据,它的准确性,测量误差,量化误差,计算中的舍入误差,以及你用它做的决定。试图将这种想法委托给制造通用工具的人注定要失败

即使使用深层域知识定义“足够平等”,也会遇到很多陷阱,例如,您可能会发现:



1“may”的意思是,这种情况比“理想”的浮点比较更常见。

您可以使用函数为double和float创建扩展,为您添加delta来执行这些检查,这将使您的代码更具可读性,如下所示:

public static class FloatExt
{
    public static bool EqualsWithDelta(this float a, float b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    public static bool EqualsWithDelta(this float a, double b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    public static bool EqualsWithDelta(this double a, float b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    public static bool EqualsWithDelta(this double a, double b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    //For the rest I'm only implementing float/float, implement the rest of combinations
    public static bool GreaterWithDelta(this float a, float b, float delta)
    {
        return a - b > delta;
    }

    public static bool LesserWithDelta(this double a, double b, float delta)
    {
        return b - a > delta;
    }
}

您可以使用函数为double和float创建扩展,以便为您添加delta来执行这些检查,这将使您的代码更具可读性,如下所示:

public static class FloatExt
{
    public static bool EqualsWithDelta(this float a, float b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    public static bool EqualsWithDelta(this float a, double b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    public static bool EqualsWithDelta(this double a, float b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    public static bool EqualsWithDelta(this double a, double b, float delta)
    {
        return Math.Abs(a - b) < delta;
    }

    //For the rest I'm only implementing float/float, implement the rest of combinations
    public static bool GreaterWithDelta(this float a, float b, float delta)
    {
        return a - b > delta;
    }

    public static bool LesserWithDelta(this double a, double b, float delta)
    {
        return b - a > delta;
    }
}

如果您知道要显示的小数位数,为什么不使用
Math.Round(a,foo)
。它将在
双0.3
浮点0.3f
上打印“理想”是基于意见的。。。这里也有类似的问题,比如“如何比较浮动”@Selvin我在问题末尾明确定义了“理想”的标准。如果你有任何关于如何更好地分阶段的意见,我很乐意听听。关于存在类似的问题,我无法在某处或其他地方找到任何能够回答这个特定问题的答案。如果你能找到我遗漏的东西,请让我知道。如果
closevery(x,y)
符合概率
P
,并且
closevery(P,100%)
是真的,这是否满足“理想”要求?如果你知道要显示的小数位数,为什么不使用
Math.Round(a,foo)
。它将在
双0.3
浮点0.3f
上打印“理想”是基于意见的。。。这里也有类似的问题,比如“如何比较浮动”@Selvin我在问题末尾明确定义了“理想”的标准。如果你有任何关于如何更好地分阶段的意见,我很乐意听听。关于存在类似的问题,我无法在某处或其他地方找到任何能够回答这个特定问题的答案。如果你能找到我遗漏的东西,请让我知道。如果
closevery(x,y)
以概率
P
,并且
closevery(P,100%)
是真的,那么这是否满足“理想”要求?UV表示“将已经定义”。UV表示“将已经定义”。
float value = 0.15f + 0.15f;
double valueb = 0.1 + 0.2;

Console.WriteLine(value.EqualsWithDelta(valueb, 0.00000001f));

var greater = valueb.GreaterWithDelta(value, 0.001f);
var lesser = value.LesserWithDelta(valueb, 0.000001f);