Math.Round(double,decimal)总是返回一致的结果 [英] Does Math.Round(double, decimal) always return consistent results
问题描述
当然,我们不应该比较计算平等所产生的浮点值,但总是使用一个小的容差,例如:
double value2 = ...
if(Math.Abs(value1 - value2)< tolerance * Math.Abs(value1))
{
...值足够接近
}
但是如果我使用Math。 Round可以始终确保结果的值是一致的,即即使四舍五入的值是一个不能完全由double值表示的值,下面的Assert总是会成功吗?
pre $
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))
{
//他们四舍五入到相同的值,是舍入确切吗?
Debug.Assert(roundedValue1 == roundedValue2);
如果不是,请提供一个反例。
编辑
double value1 = 10546080000034341D ;
double value2 = 10546080000034257D;
int小数= 0;
TestRound(value1,value2,decimals);
但是我也会对更多的数学解释感兴趣。可以执行以下任何操作的任何更具数学性的Stackoverflower的奖金upvotes:
-
找到一个反例,其中舍入的结果少于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))
{
//他们四舍五入到相同的值,是舍入确切吗?
if(roundedValue1!= roundedValue2)
{
string s =;
$ b private void button1_Click(object sender,EventArgs e)
{
for(double d = 0,inc = .000001;对于(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
十进制= 15
roundedValue1 = 1.0546080000034339
roundedValue2 = 1.0546080000034259
roundedValue1.ToString(format)= 1.054608000003430
roundedValue2.ToString(format)= 1.054608000003430
我认为这是您正在寻找的答案? / p>
如果不是,请让我知道,所以我可以测试更多。
Of course one should never compare floating point values that result from a calculation for equality, but always use a small tolerance, e.g.:
double value1 = ...
double value2 = ...
if (Math.Abs(value1 - value2) < tolerance * Math.Abs(value1))
{
... values are close enough
}
But if I use Math.Round can I always be sure that the resulting value will be consistent, i.e. will the following Assert always succeed, even when the rounded value is a value that can't be represented exactly by a double?
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);
}
}
If not please provide a counterexample.
EDIT
Thanks to astander for a counterexample generated by brute force that proves the result is not "consistent" in the general case. This counterexample has 16 significant digits in the rounded result - it also fails in the same way when scaled thus:
double value1 = 10546080000034341D;
double value2 = 10546080000034257D;
int decimals = 0;
TestRound(value1, value2, decimals);
However I'd also be interested in a more mathematical explanation. Bonus upvotes for any of the more mathematical Stackoverflowers who can do any of the following:
Find a counterexample where the rounded result has fewer than 16 significant digits.
Identify a range of values for which the rounded result will always be "consistent" as defined here (e.g. all values where the number of significant digits in the rounded result is < N).
Provide an algorithmic method to generate counterexamples.
解决方案 OK, this seems like a very technical question, so I thought brute force might tell us.
I tried the following
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);
}
I placed a breakpoint on the "string s = "";" to chcek when it enters this section,
and it entered with the following values
value1 = 1.0546080000034341
value2 = 1.0546080000034257
decimals = 15
roundedValue1 = 1.0546080000034339
roundedValue2 = 1.0546080000034259
roundedValue1.ToString(format) = 1.054608000003430
roundedValue2.ToString(format) = 1.054608000003430
I think this is the answer you were looking for?
If not, please let me know, so i can test more.
这篇关于Math.Round(double,decimal)总是返回一致的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!