2013-08-06 40 views
1

我有一個簡單的示例應用程序,我在這裏乘以並加上double變量,然後將它們與預期結果進行比較。在這兩種情況下,結果都等於預期的結果,但當我做比較失敗時。我應該如何比較這些雙打以獲得理想的結果?

static void Main(string[] args) 
{ 
    double a = 98.1; 
    double b = 107.7; 
    double c = 92.5; 
    double d = 96.5; 

    double expectedResult = 88.5; 
    double result1 = (1*2*a) + (-1*1*b); 
    double result2 = (1*2*c) + (-1*1*d);    

    Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", a, b, result1, expectedResult == result1)); 
    Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", c, d, result2, expectedResult == result2)); 

    Console.Read(); 
} 

這裏是輸出:

2x98.1 - 107.7 = 88.5 
Equal to 88.5? False 

2x92.5 - 96.5 = 88.5 
Equal to 88.5? True 

我需要能夠捕捉到它其實True在這兩種情況下。我會怎麼做?

回答

4

浮點數通常不包含數學告訴我們的確切值,因爲它們如何存儲數字。

仍然有一個可靠的比較,你需要讓一些區別:

private const double DoubleEpsilon = 2.22044604925031E-16; 

/// <summary>Determines whether <paramref name="value1"/> is very close to <paramref name="value2"/>.</summary> 
/// <param name="value1">The value1.</param> 
/// <param name="value2">The value2.</param> 
/// <returns><c>true</c> if <paramref name="value1"/> is very close to value2; otherwise, <c>false</c>.</returns> 
public static bool IsVeryCloseTo(this double value1, double value2) 
{ 
    if (value1 == value2) 
     return true; 

    var tolerance = (Math.Abs(value1) + Math.Abs(value2)) * DoubleEpsilon; 
    var difference = value1 - value2; 

    return -tolerance < difference && tolerance > difference; 
} 

也請務必閱讀this blog post

+0

+1真,但我可以問你你從哪裏拿這個公式而來? Silverlight控件工具包?還是有一些真正的數學背後的巫術?因爲... http:// stackoverflow。COM /問題/ 2411392 /雙ε-己的平等,大於,低於低於或相等到GRE – xanatos

+0

@xanatos:好問題。這是從我的一個幫手圖書館,我幾年沒有改變。我很確定我從網上獲得了它。我試圖追蹤消息來源。 –

+0

@xanatos:關於常量'DoubleEpsilon',請參閱http://en.wikipedia.org/wiki/Machine_epsilon。仍然不確定其餘的。 –

0

你四捨五入只需更改爲2級,這將給TRUE

double result1 =Math.Round ((1 * 2 * a) + (-1 * 1 * b),2); 
0

使用Math.Round()將全面RESULT1使用調試器的正確小數

result1 = Math.Round(result1, 1); 
0

result1=88.499999999999986; 
expectedResult = 88.5 

因此,使用雙時,這些是不相等的。

1

如果您需要更高精度(金錢等),然後使用decimal

var a = 98.1M; 
var b = 107.7M; 
var c = 92.5M; 
var d = 96.5M; 

var expectedResult = 88.5M; 
var result1 = (2 * a) + (-1 * b); 
var result2 = (2 * c) + (-1 * d); 

Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", a, b, result1, expectedResult == result1)); 
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", c, d, result2, expectedResult == result2)); 

輸出:

2x98.1 - 107.7 = 88.5 
Equal to 88.5? True 

2x92.5 - 96.5 = 88.5 
Equal to 88.5? True 
+0

'decimal'是* NOT *定點。它仍然是浮點數。但是內部表示不是二進制的,而是十進制的,這就是爲什麼它能像0.1這樣的「正常」數字很好地工作。簡單的證明:'Assert.Equal(1/3m * 2,2/3m); // will fail' –

+0

@DanielHilgarth我可以同意'decimal'不是固定點。但是證明是無效的,因爲對於一個固定點類型來說,斷言也會失敗。例如,在該點之後有三個固定的小數點,一個值將是'0.666',而另一個將是'0.667'。 (我假定一個定點算術,除法舍入到最接近的可表示值,而不僅僅是截斷。) –

0

有個思想是反對使用Double.Epsilon和類似號碼全校...

我認爲他們使用:(從https://stackoverflow.com/a/2411661/613130拍攝,但修改檢查IsNaNIsInfinity建議here nobugz

public static bool AboutEqual(double x, double y) 
{ 
    if (double.IsNaN(x)) return double.IsNaN(y); 
    if (double.IsInfinity(x)) return double.IsInfinity(y) && Math.Sign(x) == Math.Sign(y); 

    double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15; 
    return Math.Abs(x - y) <= epsilon; 
} 

1E-15「幻數」是基於這樣一個事實,即double的精度略高於15位。

我會補充的是,你的號碼返回:-)

相關問題