2009-04-29 204 views
228

我可以命名三個好處使用double(或float)代替decimal什麼時候應該使用double而不是小數?

  1. 使用更少的內存。
  2. 更快,因爲浮點數學運算原生支持的處理器。
  3. 可以代表更大範圍的數字。

但是,這些優點似乎只適用於計算密集型操作,如建模軟件中的那些操作。當然,如果需要精確度,例如財務計算,則不應使用雙打。那麼在「正常」應用程序中是否有任何實際的理由選擇double(或float)而不是decimal

編輯補充: 感謝所有的好評,我從他們那裏學到了。

還有一個問題:有些人認爲雙打可以更精確地表示實數。當宣佈時,我會認爲他們通常會更準確地代表他們。但是,當浮點運算執行時,準確度可能會降低(有時顯着),這是否是一個真實的陳述?

+0

另請參閱http://stackoverflow.com/questions/2545567/in-net-how-do-i-choose-between-a-decimal-and-a-double –

+3

這得到upvoted相當有規律,我仍然奮鬥用它。例如,我正在開發一個用於財務計算的應用程序,因此我在整個過程中使用了十進制。但數學和VisualBasic.Financial函數使用雙重,所以有很多轉換,我不斷猜測使用小數。 –

+0

@JamieIde這是瘋狂的金融功能使用雙倍,金錢應該始終在十進制。 –

回答

273

我認爲你已經總​​結了很好的優勢。然而你錯過了一點。 decimal類型僅在表示基數10數字(例如在貨幣/金融計算中使用的數字)時更精確。一般來說,double類型將提供至少同樣的精度(如果我錯了,有人會糾正我),對於任意實數,速度肯定會更快。簡單的結論是:在考慮使用哪一個時,請始終使用double,除非您需要decimal提供的base 10精度。

編輯:

關於你提到的有關操作之後浮點數的精度降低額外問題,這是一個稍微更微妙的問題。事實上,每次操作完成後,精度(我在這裏使用術語「可互換」來表示準確度)會穩步下降。這是由於兩個原因:a)某些數字(最明顯的小數)不能以浮點形式真實地表示,b)發生舍入誤差,就像您手動進行計算一樣。它很大程度上取決於上下文(您正在執行多少操作),但是這些錯誤是否足夠重要,以致需要考慮很多問題。在所有情況下,如果要比較理論上應該等價的兩個浮點數(但是使用不同的計算),則需要允許一定程度的容差(多少變化,但通常非常小) 。

有關可以引入精度誤差的特定情況的更詳細概述,請參閱Wikipedia article的精度部分。最後,如果你想在機器級對浮點數/操作進行認真深入的(和數學的)討論,請閱讀經常引用的文章What Every Computer Scientist Should Know About Floating-Point Arithmetic

+1

你能否提供一個基數爲10的數字的例子,在轉換爲基數2時會失去精度? –

+0

@Mark:1.000001就是一個例子,至少根據Jon Skeet的說法。 (請參閱本頁的問題3:http://www.yoda.arachsys.com/csharp/teasers-answers.html) – Noldorin

+18

@Mark:非常簡單的例子:0.1是基數爲2的週期性分數,因此無法準確表達在'雙'。現代計算機仍然會打印正確的值,但僅僅是因爲他們「猜測」了結果 - 並不是因爲它確實表達正確。 –

6

當你不需要精度的時候使用雙精度或浮點數,例如在我寫的一個平臺遊戲中,我用浮點數來存儲玩家速度。很明顯,我不需要超精確度,因爲我最終輪到Int來在屏幕上繪圖。

+3

精度是小數的唯一優點,這是正確的。你不應該問什麼時候應該使用浮點數超過小數。這應該是你的第一個想法。那麼問題是什麼時候你應該使用小數(當答案在這裏時......當精度很重要時)。 –

+2

@Daniel直,這很有趣,但我有相反的意見。我認爲使用不太精確的類型是因爲它的性能特徵等於預優化。在您意識到其優點之前,您可能需要多次支付預優化費用。 –

+3

@Michael Meadows,我可以理解這個說法。需要注意的是,過早優化的主要抱怨之一是程序員不會知道什麼會變慢。不過毫無疑問,我們知道小數比雙打慢。儘管如此,我想大多數情況下,用戶無論如何都不會注意到性能的提升。當然,在大多數情況下,精度也不是必需的。嘿。 –

50

您似乎很清楚使用浮點類型的好處。我傾向於在所有情況下設計小數點,並依靠分析器讓我知道小數點操作是否會導致瓶頸或減速。在這些情況下,我會「下注」來雙倍或浮動,但只能在內部完成,並且仔細嘗試通過限制正在執行的數學運算中的有效數字的數量來管理精度損失。

一般來說,如果你的值是瞬態的(不重用),你可以安全地使用浮點類型。浮點類型的真正問題是以下三種情況。

  1. 您正在聚集浮點值(在這種情況下,精度誤差化合物)
  2. 你建
  3. 你正在做數學與基於所述浮點值(例如在一個遞歸算法)值非常寬的數目的數字顯著(例如,123456789.1 * .000000000000000987654321

EDIT

甲ccording到reference documentation on C# decimals

小數關鍵字表示 128位的數據類型。與 浮點類型相比,小數類型 具有更高的精度和更小的範圍,因此適用於 財務和貨幣計算。

所以澄清我的上述聲明:

我傾向於在所有 情況下爲小數設計,並依靠探查讓 我知道,如果在十進制運算是 造成瓶頸或慢-downs。

我只在有小數的行業工作過。如果您正在使用phsyics或圖形引擎,那麼設計浮點類型(float或double)可能會更有益處。

小數是不是無限精確的(這是不可能代表無限精度用於在原始數據類型非整數),但它遠遠大於雙更精確的:

  • 小數= 28-29顯著數字
  • 雙= 15-16顯著數字
  • 浮子= 7個顯著數字

編輯2

迴應Konrad Rudolph的評論,項目#1(上述)絕對正確。不精確性的聚合確實複合了。請參見下面的代碼爲例:

private const float THREE_FIFTHS = 3f/5f; 
private const int ONE_MILLION = 1000000; 

public static void Main(string[] args) 
{ 
    Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10")); 
    float asSingle = 0f; 
    double asDouble = 0d; 
    decimal asDecimal = 0M; 

    for (int i = 0; i < ONE_MILLION; i++) 
    { 
     asSingle += THREE_FIFTHS; 
     asDouble += THREE_FIFTHS; 
     asDecimal += (decimal) THREE_FIFTHS; 
    } 
    Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION); 
    Console.WriteLine("Single: {0}", asSingle.ToString("F10")); 
    Console.WriteLine("Double: {0}", asDouble.ToString("F10")); 
    Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10")); 
    Console.ReadLine(); 
} 

此輸出以下:

Three Fifths: 0.6000000000 
Six Hundred Thousand: 600000.0000000000 
Single: 599093.4000000000 
Double: 599999.9999886850 
Decimal: 600000.0000000000 

正如你所看到的,即使我們從同一來源不斷增加,雙重的結果是少精確的(儘管可能會正確地回合),並且浮點數遠不夠精確,直到它減少到只有兩個有效數字。

+1

點1不正確。精度/舍入誤差只發生在鑄造中,而不是計算中。它*當然是正確的,因爲大多數數學運算是不穩定的,因此乘以誤差。但這是另一個問題,它適用於所有有限精度的數據類型,所以特別適用於小數。 –

+1

@Konrad Rudolph,請參閱「編輯2」中的示例,作爲我在第1項中試圖提出的觀點的證據。通常,這個問題並不表現出來,因爲正面的不精確性與負面的不精確性相平衡,但總計相同的數字(正如我在示例中所做的那樣)強調了這個問題。 –

+0

很好的例子。剛剛向我的初級開發人員展示過,孩子們都很驚訝。 – Machado

3

如果您需要與其他語言或平臺進行二進制運算,那麼您可能需要使用float或double,這些都是標準化的。

0

如果您重視性能而不是正確性,請使用浮點數。

+6

十進制數不是更正確的,除非在某些有時(有時並非總是)重要的有限情況下。 –

0

選擇您的應用程序的功能類型。如果你需要像財務分析那樣精確,你已經回答了你的問題。但是如果你的應用程序可以用一個估計來解決你的問題,你就可以加倍。

您的應用程序是否需要快速計算,或者他是否有足夠的時間在世界範圍內爲您提供答案?這真的取決於應用程序的類型。

飢腸轆轆的圖形?浮動或雙重就夠了。財務數據分析,流星打擊一個星球的精度?那些將需要一點精確度:)

+8

十進制數字也是估計值。它們符合金融算術的慣例,但是在涉及物理學的計算中沒有優勢。 –

21

對基數10值使用小數,例如,財務計算,如其他人所建議的那樣。

但是double對於任意計算值通常更準確。

例如,如果要計算投資組合中每條線的權重,請使用double,因爲結果會更加接近100%。

在以下示例中,doubleResult比decimalResult接近1:

// Add one third + one third + one third with decimal 
decimal decimalValue = 1M/3M; 
decimal decimalResult = decimalValue + decimalValue + decimalValue; 
// Add one third + one third + one third with double 
double doubleValue = 1D/3D; 
double doubleResult = doubleValue + doubleValue + doubleValue; 

所以再次採取組合的例子:

  • 每一行的組合中的市場價值是一個貨幣值,可能最好用十進制表示。

  • 投資組合中每條線的權重(=市場價值/ SUM(市場價值))通常更好地表示爲雙倍。

+1

+1簡單而簡單的例子! –

-1

十進制具有較寬的字節,double本身由CPU支持。十進制是基數爲10,所以計算小數時會發生小數到小數的轉換。

For accounting - decimal 
For finance - double 
For heavy computation - double 

請記住,.NET CLR只支持Math.Pow(double,double)。小數不被支持。如果該符號比小數顯示較短

.NET框架4

[SecuritySafeCritical] 
public static extern double Pow(double x, double y); 
0

雙值將序列化到科學記數法默認情況下。 (例如.00000003將是3e-8)十進制值永遠不會序列化爲科學記數法。序列化供外部消費時,這可能是一個考慮因素。

4

在一些會計,考慮使用整型代替或結合的可能性。例如,假設您所運行的規則要求每個計算結果都帶有至少6位小數,並且最終結果將四捨五入爲最接近的一分錢。

$ 100 1/6日的計算得到$ 16.66666666666666 ......,所以在工作表中攜帶着價值爲$ 16.666667。雙精度和小數精度都應該精確到小數點後6位。但是,我們可以通過將結果作爲整數16666667來避免任何累積誤差。每個後續計算都可以以相同的精度進行並進行類似的處理。繼續舉例,我計算德克薩斯州的銷售稅(16666667 * .0825 = 1375000)。添加這兩個(這是一個簡短的工作表)1666667 + 1375000 = 18041667.將小數點移回給予我們18.041667或$ 18.04。

雖然這個簡單的例子就不會產生使用雙精度或十進制累積誤差,這也很容易表現出在那裏簡單地計算雙精度或十進制和發揚會累積顯著錯誤情況。如果您在下面操作的規則需要有限的小數位數,則將每個值存儲爲整數乘以10 ^(所需的小數點位數),然後除以10 ^(所需的小數位數),以獲得實際值值將避免任何累積錯誤。

在不發生便士餾分情況下(例如,自動販賣機),沒有理由使用非整數類型的。簡單地把它看作數錢,而不是美元。我看過代碼,其中每個計算只涉及整個便士,但使用double會導致錯誤!整數只有數學解決了這個問題。所以我非常規的答案是,如果可能,放棄雙精度和小數。

2

注意:這篇文章是基於http://csharpindepth.com/Articles/General/Decimal.aspx和小數類型功能的信息我自己的是什麼意思解釋。我將假設Double是IEEE的雙精度。

注2:最小和最大在這個崗位reffer至數的大小。

「十進制」的優點。

  • 「十進制」可以精確地表示可寫爲(十分短)十進制小數的數字,double不能。在金融分類賬和類似的地方,這一點非常重要,重要的是結果必須與計算人員進行的計算完全匹配。
  • 「十進制」的尾數比「double」大得多。這意味着對於標準化範圍內的值「decimal」將具有比double更高的精度。小數

    缺點它就會慢很多(我沒有基準,但我想也許更多猜測至少一個數量級),小數將不會從任何硬件加速受益,對它進行的算術將需要相對昂貴的乘法/除以10的乘方(這比乘以2的乘方的乘法和除法要昂貴得多),以在加/減之前匹配指數並且在乘法/除法之後使指數回到範圍內。

  • 小數點將溢出更早的雙倍會。十進制只能表示數字,最多爲±2 -1。通過比較double可以代表數字達到近似值±2
  • 小數點會提前下溢。以小數表示的最小數字是±10 -28。通過對比雙可以表示的值下降到2 -149(約10 -45 )如果subnromal支援數字和2 -126(約10 -38 ),如果他們不。
  • 十進制佔用兩倍的內存。

我的意見是,你應該默認使用「十進制」金錢工作和其他情況下,其中匹配人的計算是重要的,你應該使用雙重作爲您的默認選擇餘下的時間。

0

取決於你需要什麼。

因爲float和double是二進制數據類型,你有一些 diifculties和errrors在發號的方式,因此例如雙將0.1四捨五入爲0.100000001490116,雙也會輪1/3〜0.33333334326441。簡單地說,並非所有實數都有精確的雙精度表示形式

幸運的是C#還支持所謂的十進制浮點運算,其中數字通過十進制數字系統而不是二進制系統表示。因此,在存儲和處理浮點數時,十進制浮點數算術不會丟失精度。這使得它非常適合需要高精度的計算。

相關問題