当然,永远不应该比较相等计算产生的浮点值,但总是使用一个小容差,例如:
double value1 = ...
double value2 = ...
if (Math.Abs(value1 - value2) < tolerance * Math.Abs(value1))
{
... values are close enough
}
但是如果我使用Math.Round,我总是可以确定结果值是否一致,即即使舍入值是一个无法用双精确表示的值,下面的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位有效数字的反例。
确定一系列值,其舍入结果将始终为“一致”,如此处所定义(例如,舍入结果中有效数字的数字
提供一种算法方法来生成反例。
答案 0 :(得分:2)
好的,这似乎是一个非常技术性的问题,所以我认为蛮力可能会告诉我们。
我尝试了以下
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 =”“;”上放了一个断点当它进入这个部分时chcek,
并输入以下值
value1 = 1.0546080000034341
value2 = 1.0546080000034257
decimals = 15
roundedValue1 = 1.0546080000034339
roundedValue2 = 1.0546080000034259
roundedValue1.ToString(format) = 1.054608000003430
roundedValue2.ToString(format) = 1.054608000003430
我认为这是您正在寻找的答案?
如果没有,请告诉我,以便我可以测试更多。
答案 1 :(得分:2)
虽然浮点计算的精度有限,因此不精确,但它们是确定性的。因此,如果对相同顺序的相同值使用相同的计算,则应始终获得相同的结果。因此,对相同值使用相同的舍入方法将得到相同的结果。
浮点计算的问题在于,数学上给出相同结果的两个不同计算的结果(e.q。Sqrt(x)*Sqrt(x)==x
)可能并且很可能因计算中的舍入误差而不同