2

将 Single 值转换为 Double 值时遇到问题。

BitStream 提供的单曲是简单的 2 到 6 位小数,在许多情况下,简单到 0.4、0.94、0.6 等(我应该注意,我收到的文档指出它们是浮点数(Java 中),来自我的理解与.NET 中的 Single 相同。

我最终需要将这些值作为双精度值,因为它们将用作 Point3D 对象(X、Y 和 Z)的坐标,并最终用于其他需要双精度值的应用程序的 API。

但是,当我使用 CDbl(valueAsSingle) 或 Ctype(valueAsSingle, Double) 执行转换时,该数字在 Double 中添加了额外的小数位,在第 9 位和更晚的小数位。这会导致最终需要使用这些值的应用程序出现问题。

首先,我很好奇为什么会这样?其次,如果我只是将 Single 转换为 String,然后执行 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
4

4 回答 4

2

使用以下

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 数字,表示您想要多少分数

所以

上面的代码将返回:

DX: 0.4
DY: 0.94
DZ: 0.6

我假设您使用的是 .net 4.0

于 2013-12-20T16:25:59.650 回答
2

好的,在一位同事的指导下,我发现这篇维基百科文章讨论了单精度的准确性问题。我不得不承认我读它时眼睛发呆,但也许你会玩得更好。

我无法谈论您的具体情况,但 ToStringing/Converting 应该没有太大问题。或者,您可以根据 Imrans 的回答对其进行舍入。

于 2013-12-20T16:41:53.183 回答
1

不理会这些值(抵制Math.Round()诱惑)并处理输出。经过多年的尝试,我以这个结尾(通过C#http://www.developerfusion.com/tools/convert/csharp-to-vb翻译):VB.NET

<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
于 2013-12-20T18:25:50.757 回答
-1

试试这个:将“转换为字符串”的单曲转换为双曲。

Dim SingleX as single = 0.4
Dim SingleX as single = 0.94
Dim SingleX as single = 0.8
Dim DoubleX, DoubleY, DoubleZ as double
Double.TryParse(SingleX.tostring, DoubleX)
Double.TryParse(SingleY.tostring, DoubleY)
Double.TryParse(SingleZ.tostring, DoubleZ)
DoubleX = 0.4
DoubleY = 0.94
DoubleZ = 0.6
于 2020-04-29T20:08:35.510 回答