【问题标题】:How to comparing two x significant doubles correctly [duplicate]如何正确比较两个x显着双打[重复]
【发布时间】:2018-06-25 13:56:29
【问题描述】:

这不是重复的问题。问题中有一个答案。希望对您有所帮助。

有两个doubles 具有相同的小数值。

(对不起,这不是一个好案例。因为它有时会返回false,但我找不到案例。如果你尝试这个案例,它可能没有任何问题。所以不要浪费时间测试它。)

double a = 0.70448;
double b = 0.70441;

我只想将它们与 4 位小数进行比较。

我有这个辅助函数可以先将它们向下舍入到小数点后 4 位。

public static double RoundDown(this double value, int decimals)
{
    var multiplier = Math.Pow(10, decimals);
    return Math.Floor(value * multiplier) / multiplier;
}

然后我想检查a 是否大于b,如下所示: RoundDown(a, 4) > RoundDown(b, 4)

有时,在某些情况下,即使它们看起来相等,它也会返回 true。我非常了解这是浮动问题,所以我想知道是否有任何优雅的解决方案来比较它们。

更新:

我试图将它相乘并以整数比较它们。但是,对于这个解决方案,我需要处理双无穷大和 NAN。

    private static CompareResult Compare(double a, double b, double decimals = 0)
    {
        var multiplier = Math.Pow(10, decimals);
        var aInt = Convert.ToInt32(a * multiplier);
        var bInt = Convert.ToInt32(b * multiplier);
        return aInt > bInt ? CompareResult.Greater : aInt < bInt ? CompareResult.Less : CompareResult.Equal;
    }

    private enum CompareResult
    {
        Greater,
        Less,
        Equal
    }

System.OverflowException 如果 double 之一大于 int max 或 infinity 则抛出。此外,这不是比较双倍的优雅方式。

重要提示

我不会用 x 有效数字四舍五入。我已经在我的问题中提供了这个解决方案,我的问题是:即使向下舍入到 x 有效数字,比较它们时也会返回 true。

再次

我没有找到将双精度数舍入或截断为 x 有效数字的方法。这部分我没有问题。

回答

感谢@m88 的回答。但它仍然无法解决我的问题。 我终于使用 sigma 解决了这个问题。 (参考:http://forums.codeguru.com/showthread.php?506300-float-double-value-comparison-significant-figures。)

感谢一些人误解了问题并将其投票为重复问题。我不能为面临同样问题的其他人发布我的答案。所以我在我的问题中发布了答案。我希望它可以帮助其他人。

public static int CompareTo(this double value1, double value2, int decimals)
{
    var diff = value1 - value2;
    var sigma = Math.Pow(10, -decimals - 1);
    return Math.Abs(diff) < sigma ? 0 : diff > 0 ? 1 : -1;
}

【问题讨论】:

  • @Equalsk 请仔细阅读我的问题。我已经告诉过你将双精度数舍入到 x 有效数字的方法。我想要的是正确比较它们。
  • 请仔细阅读链接的副本,而不仅仅是标题。它演示了 truncation,这是您在 rounding 之后所追求的。
  • @Equalsk 我已经读过了。我想要的是正确比较,而不是截断舍入。检查这个:forums.codeguru.com/…
  • @Equalsk 或者你想说问题出在向下舍入方法上?还是 Math.Floor 导致比较失败?
  • @Servy 无论如何,我已经一次又一次地阅读了可能重复的问题。首先,它没有公认的答案。其次,投票最多的答案已经是我当前的四舍五入解决方案。请仔细准备我的问题,而不是只阅读第一段。我想比较它们,但不想舍入/截断它们。

标签: c# compare double


【解决方案1】:

如果使用Math.Round 方法将ab 舍入到小数点后4 位,a (0.7045) 将始终大于b (0.7044):

const double a = 0.70448;
const double b = 0.70441;
if (Math.Round(a, 4) > Math.Round(b, 4))
...

如果您想截断这些值,您需要了解并非所有分数都可以在double 中准确表示的事实。如果您想要“精确”截断,您可以考虑将double 值转换为string,截断string,然后将截断的string 值转换回double。像这样的:

private static double Truncate(double d, int decimals)
{
    string s = d.ToString(System.Globalization.CultureInfo.InvariantCulture);
    int index = s.IndexOf(System.Globalization.CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator);
    if (index > -1)
        return Convert.ToDouble($"{s.Substring(0, index + 1)}{s.Substring(index + 1, decimals)}", System.Globalization.CultureInfo.InvariantCulture);

    return d;
}

用法:

const double a = 0.70448;
const double b = 0.70441;

if (Truncate(a, 4) >= Truncate(b, 4))
....

显然,如果您不想像聊天中所说的那样出现任何“浮动问题”,则无法使用浮点数据类型。

【讨论】:

  • 我需要检查greater than 不带equal 大小写,四舍五入到小数点后四位。
  • @shtse8 有什么区别? a 仍然大于 b,只需从检查中删除 =
  • 四舍五入到小数点后,它们应该相等。条件应该返回false。但是对于某些情况(有浮动问题,很难找到这些情况),即使它们看起来相等,它也会返回 true。
  • @shtse8:如前所述,a 将始终大于 b 给定这些值。
  • “四舍五入后,它们应该相等”。不。为什么他们会是平等的?
【解决方案2】:

你想要截断,而不是舍入:

double a = Math.Truncate(100 * 0.70448) / 100;
double b = Math.Truncate(100 * 0.70441) / 100;

if (a > b)
{
    // ...
}

请注意,根据@mm8 的评论,double 中无法准确表示分数。

【讨论】:

  • 我正在使用类似的解决方案,但我发现它会在某些特殊情况下返回 true。 (我没有找到这种情况,因为很难产生相同的浮点值。)
  • 分数不能准确地用双精度表示。如果您想要“精确”截断,您可以考虑将双精度值转换为字符串,截断字符串,然后将截断的值转换回双精度。
  • @mm8 同意,将评论合并到答案中。
  • 是的,这也是我的方向。关于我的问题,我发布了另一个解决方案以整数比较它们,并解释了为什么该解决方案不够好。我想知道是否有更好的方法来处理这种情况 - 正确比较两个 x 显着双打。 (不是 15 个)。
  • 是的,字符串就是字符串。截断值时不会损失精度。您只需从某个索引中“剪切”字符串即可。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-29
  • 1970-01-01
  • 2014-11-12
  • 1970-01-01
相关资源
最近更新 更多