【问题标题】:Is it a good idea to compare double.MaxValue for equality?比较 double.MaxValue 是否相等是个好主意吗?
【发布时间】:2011-04-21 22:10:26
【问题描述】:

可以对 float... 或 MinValue 提出相同的问题。

我正在考虑将其用作特殊值。我会因为精度而看到错误吗?我不希望对这些数字进行算术运算,只需设置它们即可。

澄清:我将其用作哨兵值。

它是在 C# 规范中描述的吗?

【问题讨论】:

  • 我知道这是基于浮点数比较理论的其他人的副本。我说如果双精度大于 MaxValue 那么它会溢出,所以除非你正在测试看看你是否即将溢出,那么我认为测试到一个安全的精度极限会更好。跨度>
  • 您能否为您的问题添加更多详细信息?我不明白你想比较什么。
  • @Roflcoptr:添加了一些细节。
  • FWIW,有一种情况是我以这种方式使用 MaxValue/MinValue。频繁地。当找到一个集合的最小值时,我从 MaxValue 开始。所以我不需要额外的垃圾来启动 min-finder,也不需要额外的循环测试。 float minA = float.MaxValue; foreach (float a ...) if (a < minA){ minA = a; ... } 当我需要跟踪与as 相关联的 other 值时,我会这样做。

标签: c# .net cls-compliant


【解决方案1】:

这取决于你如何使用它。

如果您使用 double.MaxValue 作为具有特殊语义的标记或标记值,那么是的,这只是您要比较的位模式。例如,您可以使用double.MaxValue 来指示“未初始化”或“未知”值。还有其他方法可以做到这一点(例如,使用可为空的 double?),但假设该值不会自然地出现在您的域中,使用 double.MaxValue 也是合理的。

但是,如果您有一些任意的 double 值,并且您想查看它是否“等于”double.MaxValue,那么您需要查看这些数字是否在每个值的某个小范围内(epsilon)其他,因为在计算您的其他 double 值时可能会丢失一些精度。这里要注意的问题是超出double.MaxValue 的值,会造成溢出情况。

【讨论】:

    【解决方案2】:

    如果您比较 double.MaxValuedouble.MaxValue,是的,它们是相同的。二进制表示是相同的,不会有问题。另一方面,如果您尝试以下操作:

    double myDouble = (double.MaxValue - 3.1415) / 2;
    if((myDouble * 2) + 3.1415 == double.MaxValue)
    {
        ...
    }
    

    那么是的,您可能会开始看到奇怪的精度问题弹出。

    以下是无法与自身进行比较的特殊常量。其他任何事情都是公平的游戏。

    • NaN
    • 负无穷
    • 正无穷

    【讨论】:

    • 我在某处读到,将无穷大(正数或负数)与 == 进行比较是个坏主意。这就是为什么 double 对那些具有实用功能的原因。
    • 啊,是的,我忘记了这些。这同样适用于它们作为 NaN。
    • 我已经更新了这个以反映需要特殊测试的常量。
    • @Chris:如果四舍五入的话,您要达到的是 Math.PI,或者 3.1416。不过不要混淆这个问题:)
    • @GregC 我知道我写了什么。我不想要所有其他数字,PI 太精确了。是的,我说过。太精确了。
    【解决方案3】:

    如果您想要一个“特殊”值,我的建议是改用Nullable

    double? val = ...;
    
    if(val.HasValue)
        // do something with val.Value
    

    【讨论】:

    • 我已经用完了 null、NaN、Positive 和 Negative Inf.
    • @GregC:嗯。复数的时候了,我的朋友
    • @GregC 你的设计肯定有问题。听说过例外吗?
    • 我知道。明天我会去和编写我们的代码生成器的人谈谈。 :)
    【解决方案4】:

    使用“特殊值”通常是不好的做法。我更喜欢使用带有某种状态代码的对象,然后是一个 double(/float/whatever),只有在状态非异常时才会填充。

    public class CalcNumber
    {
        public CalcNumberStatus Status {get; private set;}
        public double Value {get; private set;}
    
    
        public CalcNumber(double value)
        {
            Status = CalcNumberStatus.Normal;
            Value = value;
        }
    
        public CalcNumber(CalcNumberStatus status)
        {
            if(status == CalcNumberStatus.Normal)
            {
                throw new Exception("Cannot create a normal CalcNumber without a value");
            }
            Status = status;
            Value = 0;
        }
    }
    public enum CalcNumberStatus 
    {
        Normal,
        Error
    }
    

    如果需要,您甚至可以进行一些花哨的运算符重载,以便于转换和算术。

    关于精度问题,因为听起来你不打算对这个数字进行算术运算,所以你不应该遇到阻止相等检查工作的精度问题。

    【讨论】:

    • 我在公司使用的 codegen 中有一些(可以说)自我强加的限制。我必须在这里坚持原始类型。
    【解决方案5】:

    我认为这应该不是问题。我没有技术解释,但我已经多次使用 MaxValue 或 MinValue 进行比较,这从来都不是问题。

    【讨论】:

      猜你喜欢
      • 2013-08-18
      • 2016-10-20
      • 1970-01-01
      • 2013-07-26
      • 2018-08-17
      • 2011-03-06
      • 2021-09-14
      • 2023-03-11
      • 2010-12-05
      相关资源
      最近更新 更多