.net - Math.Round(double,decimal) 是否总是返回一致的结果

标签 .net floating-point

当然,永远不要比较由相等性计算得出的浮点值,而应始终使用较小的容差,例如:

double value1 = ... 
double value2 = ...
if (Math.Abs(value1 - value2) < tolerance * Math.Abs(value1))
{
    ... values are close enough
}

但是,如果我使用 Math.Round,我是否可以始终确保结果值是一致的,即即使舍入后的值是不能由 double 值精确表示的值,以下 Assert 是否总是成功?
public static void TestRound(double value1, double value2, int decimals)
{
    double roundedValue1 = Math.Round(value1, decimals);
    double roundedValue2 = Math.Round(value2, decimals);

    string format = "N" + decimals.ToString();
    if (roundedValue1.ToString(format) == roundedValue2.ToString(format))
    {
        // They rounded to the same value, was the rounding exact?
        Debug.Assert(roundedValue1 == roundedValue2);
    }
}

如果不是,请提供一个反例。

编辑

感谢 astander对于由蛮力产生的反例,证明结果在一般情况下不“一致”。这个反例在四舍五入的结果中有 16 位有效数字——它在缩放时也以同样的方式失败:
        double value1 = 10546080000034341D;
        double value2 = 10546080000034257D;
        int decimals = 0;
        TestRound(value1, value2, decimals);

但是,我也对更数学化的解释感兴趣。任何更数学化的 Stackoverflowers 都可以做以下任何一项:
  • 找出一个四舍五入的结果少于 16 位有效数字的反例。
  • 确定舍入结果 的值范围将 始终如此处定义的那样“一致”(例如,舍入结果中有效位数< N 的所有值)。
  • 提供生成反例的算法方法。
  • 最佳答案

    好吧,这似乎是一个非常技术性的问题,所以我认为蛮力可能会告诉我们。

    我尝试了以下

    public static void TestRound(double value1, double value2, int decimals)
    {
        double roundedValue1 = Math.Round(value1, decimals);
        double roundedValue2 = Math.Round(value2, decimals);
    
        string format = "N" + decimals.ToString();
        if (roundedValue1.ToString(format) == roundedValue2.ToString(format))
        {
            // They rounded to the same value, was the rounding exact?
            if (roundedValue1 != roundedValue2)
            {
                string s = "";
            }
        }
    }
    private void button1_Click(object sender, EventArgs e)
    {
        for (double d = 0, inc = .000001; d < 1000; d += inc)
            for (int p = 0; p <= 15; p++)
                TestRound(Math.Pow(Math.Pow(d, inc), 1 / inc), d, p);
    }
    

    我在 "string s = "";"上放置了一个断点当它进入这个部分时检查,

    并输入以下值
    value1 = 1.0546080000034341
    value2 = 1.0546080000034257
    decimals = 15
    roundedValue1 = 1.0546080000034339
    roundedValue2 = 1.0546080000034259
    roundedValue1.ToString(format) = 1.054608000003430
    roundedValue2.ToString(format) = 1.054608000003430
    

    我想这就是你要找的答案?

    如果没有,请告诉我,以便我可以测试更多。

    关于.net - Math.Round(double,decimal) 是否总是返回一致的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1832335/

    相关文章:

    .net - 什么会导致 WPF 应用程序因 AppHangB1 问题事件名称而崩溃?

    c# - 我应该为远程处理程序集强命名吗?

    c - c中有多少种浮点类型?

    c - float 与 c 中的双重奇怪行为

    R:如何让 gamma() 返回实际数字而不是 Inf

    .net - ASP.Net Web 应用程序的分析器?

    c# - Unity Application Block,如何将参数传递给注入(inject)工厂?

    c# - 如何使用 JSON.Net 将 JsonExtensionData (Dictionary<string, JToken>) 应用于另一个对象

    c++ - 32 位数字的十六进制表示

    java - 为什么 Math.round() 为 NaN 参数返回 0?