2013-12-20 148 views
1

將單個值轉換爲雙值值時出現問題。將單個值轉換爲雙倍值

由BitStream提供的單數是簡單的2至6位十進制數,在許多情況下,只需0.4,0.94,0.6等簡單(我應該注意,我收到的文檔聲明它們是Floats(在Java中),根據我的理解,它與.NET中的Single相同。

我最終需要這些值作爲雙精度值,因爲它們將用作Point3D對象(X,Y和Z)的座標,並最終用於但是,當我使用CDbl(valueAsSingle)或Ctype(valueAsSingle,Double)執行轉換時,該數字在Double中添加了額外的小數位數,第9個數字一個nd小數點後一位。這會導致最終需要使用這些值的應用程序出現問題。

首先,我很好奇爲什麼會發生這種情況?其次,如果我簡單地將Single轉換爲字符串,然後執行Double.TryParse(valueAsString),可能會出現問題,以下是一個非常簡單的示例。其中

Sub Main() 
    Dim SingleX As Single = 0.4 
    Dim SingleY As Single = 0.94 
    Dim SingleZ As Single = 0.6 

    Console.WriteLine(String.Concat("SX: ", SingleX, ControlChars.NewLine, "SY: ", SingleY, ControlChars.NewLine, "SZ: ", SingleZ, ControlChars.NewLine)) 

    Dim DoubleX As Double = CDbl(SingleX) 
    Dim DoubleY As Double = CDbl(SingleY) 
    Dim DoubleZ As Double = CDbl(SingleZ) 

    Console.WriteLine(String.Concat("DX: ", DoubleX, ControlChars.NewLine, "DY: ", DoubleY, ControlChars.NewLine, "DZ: ", DoubleZ)) 

    Console.ReadLine() 
End Sub 

的結果是

SX: 0.4 
SY: 0.94 
SZ: 0.6 

DX: 0.400000005960464 
DY: 0.939999997615814 
DZ: 0.600000023841858 
+0

那奇怪的行爲。我很想知道爲什麼會發生這種行爲。 –

+0

如果要使用從數字到字符串的雙向直接轉換,並確保使用'x.ToString(「R」)'(請參閱http://msdn.microsoft.com/zh-cn/library/dwhawy9k( v = vs.110).aspx) – ja72

+0

阿波羅計劃有同樣的問題。我認爲有些事情在他們想出來之前就爆發了。 – blindguy

回答

2

好了,用某位同事的指針,我發現這個Wikipedia一篇文章,談到與單精度準確的問題。閱讀時我必須承認我的眼睛釉,但也許你會有更好的時間。

我不能說你的具體情況,但ToStringing /轉換應該沒有太大的問題。或者你可以按照Imrans的回答將它四捨五入。

+0

這確實揭示了這個問題,謝謝!事實上,這幫助我意識到,如果我想將小數位數進一步推出,關於舍入的其他答案之一可能會導致問題。在這種情況下,我需要在16個地方的某些情況下準確。我展示的例子只是一些容易顯示問題的示例值,但最終提供的其他值在小數位數方面更深。 – Jeremy

+0

我將此標記爲正確的答案,基於Wikipedia post的鏈接。它最終幫助我理解了「爲什麼」這是我的主要問題。雖然我應該提到所有的答案都非常有幫助。由於分數太少,我無法將它們標記爲有用。 – Jeremy

1

使用以下

Dim DoubleX As Double = Math.Round(Convert.ToDouble(SingleX),2) 
Dim DoubleY As Double = Math.Round(Convert.ToDouble(SingleY),2) 
Dim DoubleZ As Double = Math.Round(Convert.ToDouble(SingleZ),2) 

2是INT位,表明有多少分數,你想

所以

上面的代碼將r E打開:

DX: 0.4 
DY: 0.94 
DZ: 0.6 

我假設你正在使用.NET 4.0

1

保留這些值(抵制Math.Round()的誘惑)並處理輸出。經過多年的努力我這個(譯自C#VB.NET通過http://www.developerfusion.com/tools/convert/csharp-to-vb)結束:

<System.Runtime.CompilerServices.Extension> _ 
Public Shared Function Nice(x As Double, significant_digits As Integer) As String 
    'Check for special numbers and non-numbers 
    If Double.IsInfinity(x) OrElse Double.IsNaN(x) Then 
     Return x.ToString() 
    End If 
    ' extract sign so we deal with positive numbers only 
    Dim sign As Integer = Math.Sign(x) 
    x = Math.Abs(x) 
    Dim fmt As String 
    x = Math.Round(x, 15) 
    If x = 0 Then 
     fmt = New String("#"C, significant_digits - 1) 
     Return String.Format("{0:0." & fmt & "}", x) 
    End If 
    ' get scientific exponent, 10^3, 10^6, ... 
    Dim sci As Integer = CInt(Math.Floor(Math.Log(x, 10)/3)) * 3 
    ' biases decimal when exponent is negative 
    ' example 0.123 shows as 0.123 instead of 123e-3 
    If sci<0 Then 
     sci += 3 
    End If 
    ' scale number to exponent found 
    x = x * Math.Pow(10, -sci) 
    ' find number of digits to the left of the decimal 
    Dim dg As Integer = CInt(Math.Floor(Math.Log(x, 10))) + 1 
    ' adjust decimals to display 
    Dim decimals As Integer = Math.Min(significant_digits - dg, 15) 
    ' format for the decimals 
    fmt = New String("#"C, decimals) 
    Dim num = Math.Round(x, decimals) 
    If sci = 0 Then 
     'no exponent 
     Return String.Format("{0}{1:0." & fmt & "}", If(sign < 0, "-", String.Empty), num) 
    End If 
    Return String.Format("{0}{1:0." & fmt & "}e{2}", If(sign < 0, "-", String.Empty), num, sci) 
End Function 

下面是一些例子:

x      Nice(x,4) 
0.9f     0.9 
0.96666666f    0.9667 
96666f     96.67e3 
9666666f    9.667e6 
0.939999997615814e-5f 0.0094e-3 
0.939999997615814f  0.94 
0.939999997615814e-5f 0.94e3