2013-12-20 71 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