2012-09-13 41 views
1

可能這是一個非常基本的問題,但我真的很想知道真的發生了什麼。Convert.ToDouble(object)中的小數精度是否依賴於文化?

例如,如果我們做了以下的C#:

object obj = "330.1500249000119"; 
var val = Convert.ToDouble(obj); 

瓦爾變爲:330.15002490001189

的問題是,爲什麼去年9是89更換?我們能阻止它發生這種情況嗎?這個精度是否依賴於當前的文化?

+0

imho第一個var是一個字符串/十進制非常精確,但較慢的計算。第二個變量是一個非常快速的雙重計算,但並不是所有的值都可以編碼,330.15002490001189當然是330.1500249000119中最接近的雙倍編碼值。 – tschmit007

回答

4

這與文化無關。有些數字不能完全以2爲底的數字表示,就像基數爲10 1/3的數字不能完全代表.3333333

請注意,在您的具體情況下,您輸入的數字多於數據類型允許:有Double的有效數字是15-16(取決於範圍),你的號碼超出。

取而代之的是Double,你可以在這種情況下使用Decimal

object obj = "330.1500249000119"; 
var val = Convert.ToDecimal(obj); 
+1

3/10正好是十進制的.3。也許你的意思是1/3? –

+0

@Chris確實 - 你在我的編輯之前:) –

+0

@PhilipRieck - 現在好了,val包含與原始obj完全相同的數字。但是,現在,如果我們再次把val加倍,那麼也是這樣的;將最後9個替換爲89.問題是我需要兩個完全相同的數字,這是可能的嗎?我標記它的答案,因爲它回答了我原來的問題:) – Baig

0

不,你不能阻止它發生。您正在解析具有數據類型可以表示的更多數字的值。

精度不依賴於文化。 A double始終具有相同的精度。

所以,如果你不想讓它發生,那麼根本就不要這樣做。如果您不想要浮點數的有限精度的影響,請不要使用浮點數。如果您要使用固定點數(十進制)代替,它可以精確地表示數值。

+0

爲什麼downvote?如果你不解釋你認爲是錯誤的,它不能改善答案。 – Guffa

+0

我不是downvoter,但我認爲你的迴應是不準確的。這不是一個數字問題,而是一個編碼問題:確切的值不能被編碼爲雙精度值,因此最接近的值被編碼。 – tschmit007

+0

@Guffa但生成的double有* more *數字比輸入字符串。 –

-1

一個CPU代表8個字節雙打。其分爲1個符號位,11位指數(「範圍」)和52位尾數(「精度」)。 您的範圍和精度有限。

的常數C DBL_DIG<float.h>告訴你,這樣的雙重只能代表15位精確,而不是更多。但是這個數字完全依賴於你的c庫和CPU。

330.1500249000119包含18位數字,所以它將四捨五入爲330.150024900012。 330.15002490001189只有一個,這很好。通常你應該預期1.189比1.2。

對於後面的精確數學,請閱讀David Goldberg的「每個計算機科學家應該知道的關於浮點運算的知識」,ACM Computing Surveys 23,1(1991-03),5-48。如果你對細節感興趣,這是值得閱讀的,但它確實需要計算機科學的背景知識。 http://www.validlab.com/goldberg/paper.pdf

您可以通過在HW使用更好的浮點類型,如長雙或__float128,或使用更好的CPU,像的Sparc64或S390,其使用41位(__float128)本身,只要雙阻止這種情況發生。

是的,使用UltraSparc/Niagara或IBM S390是文化。

通常的答案是:使用長雙,夥計。在英特爾(18位數字)和多個powerpc(31位數字)上給你兩個字節,在sparc64/s390上給你41個字節。

+0

長雙?我一定錯過了C#規範。 – user7116