【问题标题】:Converting a number to normalized scientific notation将数字转换为标准化的科学记数法
【发布时间】:2015-04-04 23:09:38
【问题描述】:

我正在尝试创建一种将数字转换为标准化科学记数法的方法,这是我用来计算尾数和指数的代码:

ConvNSN 1000, M, P
MsgBox M & "e" & P

Sub ConvNSN(N, M, P)
    If N = 0 Then
        P = 0
        M = 0
    Else
        P = Int(Log(Abs(N)) / Log(10))
        M = N / 10 ^ P
    End If
End Sub

我面临的问题是此代码为某些数字提供了错误的指数值,例如 1000、10E+6、10E+9、10E+12、10E+13 等...对于 1000 转换应该是 1e3 ,但不是 10e2。很明显数字也有同样的问题,对数接近整数,比如Log(1 - 5.55111512312578E-17) / Log(10),结果是0,但是1 - 5.55111512312578E-17小于1,结果一定是负数。

我怎样才能摆脱Double 类型不精确,并让这段代码正常工作?

更新

我假设以标准化科学计数法计算尾数和指数的最快和相当准确的方法可能如下:

Sub ConvNSN(N, M, P)
    Dim A
    If N = 0 Then
        P = 0
        M = 0
        Exit Sub
    End If
    A = Abs(N)
    If A < 1 Then
        P = Int(Log(A) / Log(10))
    Else
        P = Int(Log(A) / Log(10) * (2 + Log(.1) / Log(10)))
    End If
    M = N / 10 ^ P
End Sub

或者另一个,基于@Bob的解决方案:

Sub ConvNSN(N, M, P)
    If N = 0 Then
        P = 0
        M = 0
    Else
        P = Int(Log(Abs(N)) / Log(10))
        M = N / 10 ^ P
    End If
    If Abs(M) = "10" Then
        M = M / 10
        P = P + 1
    End If
End Sub

第一个稍微快一点。它们都处理从 -322 到 308 的指数,但返回未归一化的尾数,其幂小于 -310 的 10。我还没有用数字对它们进行测试,它们的对数略小但非常接近整数值。

更新 2

我决定在这里附加一个额外的Sub ConvEN(),允许用从“p”到“T”的SI前缀表示工程符号中的数字:

N = .0000456789
ConvNSN N, M, P
M = Round(M, 2)
ConvEN M, P, R, S
MsgBox R & " " & S & "Units"

Sub ConvNSN(N, M, P)
    Dim A
    If N = 0 Then
        P = 0
        M = 0
        Exit Sub
    End If
    A = Abs(N)
    If A < 1 Then
        P = Int(Log(A) / Log(10))
    Else
        P = Int(Log(A) / Log(10) * (2 + Log(.1) / Log(10)))
    End If
    M = N / 10 ^ P
End Sub

Sub ConvEN(M, P, R, S)
    DIM Q, P3
    Q = int(P / 3)
    P3 = Q * 3
    If Q >= -4 And Q <= 4 Then
        S = Array("p", "n", ChrW(&H03BC), "m", "", "k", "M", "G", "T")(Q + 4)
    Else
        S = "e" & P3 & " "
    End If
    R = M * 10 ^ (P - P3)
End Sub

【问题讨论】:

    标签: vbscript wsh double-precision scientific-notation


    【解决方案1】:

    试试这个:

    ConvNSN 1000, M, P
    MsgBox M & "E" & P
    
    ConvNSN 0.00000000000000001234, M, P
    MsgBox M & "E" & P
    
    ConvNSN -0.00000000000000001234, M, P
    MsgBox M & "E" & P
    
    Sub ConvNSN(N, M, P)
      P = 0
      If N < 0 Then
        S = -1
      ElseIf N > 0 Then
        S = 1
      Else
        M = 0
        Exit Sub
      End If
      M = Abs(N)
      If M >= 10 Then
        While M >= 10
          M = M / 10
          P = P + 1
        Wend
        M = M * S
        Exit Sub
      End If
      If M < 1 Then
        While M < 1
          M = M * 10
          P = P - 1
        Wend
        M = M * S
        Exit Sub
      End If
    End Sub
    

    基于 cmets,我以自己的方式重写了这个,忽略了 OP 中的结构。

    MsgBox NSN(-0.0000000000000000000123456789,4)
    MsgBox NSN(1234567890000000000000000000,4)
    
    Function NSN(Number, Accuracy)
      Exponent = 0
      If Number > 0 Then
        Sign = 1
      ElseIf Number < 0 Then
        Sign = -1
      Else
        NSN = 0
        Exit Function
      End If
      Number = Number * Sign
      If Number >= 10 Then
        While Number >= 10
          Number = Number / 10
          Exponent = Exponent + 1
        Wend
      ElseIf Number < 1 Then
        While Number < 1
          Number = Number * 10
          Exponent = Exponent - 1
        Wend
      End If
      Number = Round(Number, Accuracy)
      If Number = "10" Then
        Number = 1
        Exponent = Exponent + 1
      End If
      Number = Number * Sign
      If Exponent = 0 Then
        NSN = Number
      Else
        NSN = Number & "E" & Exponent
      End If
    End Function
    

    【讨论】:

    • 如果M &gt;= 1 and M &lt;= 10 怎么办?试试ConvNSN 5, M, P
    • 1 到 10 之间的数字通常不使用科学计数法书写。科学记数法是科学家轻松处理非常大或非常小的数字的方式。
    • 似乎Round() 可能会有所帮助。我注意到NSN(1e-14, 15) 返回10E-13。获得正确结果的唯一方法是切断最后几位数字,因此NSN(1e-14, 14) 返回1E-14。如果不需要高精度(例如显示值),它就适合,因为 Double 的机器 epsilon 是 1.11e-16。我也试过ConvNSN 1000, M, P: MsgBox M &amp; "E" &amp; P,它仍然为我提供10E2
    • 我发现并纠正了 NSN(1e-14,15) 的问题,它现在应返回 1E-14。 ConvNSN 1000, M, P: MsgBox M & "E" & P 对我来说很好,使用我第一个示例中的代码返回 1E3。这实际上是它测试的第一件事。
    • 我认为在 VBS 中使用这样的数学运算只能获得 14 的准确度。如果您需要更多内容,则可以使用@Trigger 建议的字符串操作来编写一些东西。在我看来,NSN 函数比我的例子中的 ConvNSN sub 更好。
    【解决方案2】:

    使用字符串而不是数学会有所帮助。添加您自己的错误检查。

    Num = "1000000.0005"
    NumOfDigits = 4
    
    Mag = Instr(Num, ".")
    Num = Replace(Num, ".", "")
    MSD = Left(Num, 1)
    Rest = Mid(num, 2, NumOfDigits)
    
    
    msgbox MSD & "." & Rest & " x 10^" & (Mag -2)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-23
      • 2022-10-06
      • 2015-07-03
      • 2019-04-22
      • 1970-01-01
      • 2019-04-21
      • 2017-11-27
      • 1970-01-01
      相关资源
      最近更新 更多