将数字转换为规范化的科学记数法

Converting a number to normalized scientific notation

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

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 的指数,但 return 不是 10 的幂小于 -310 的归一化尾数。我还没有用数字测试它们,它们的对数略少但非常接近整数值。

更新 2

我决定在这里附加一个额外的 Sub ConvEN(),允许用 SI 前缀表示从 "p" 到 "T":

的工程符号中的数字
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

试试这个:

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

根据评论,我按照自己的方式重写了这篇文章,忽略了 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

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

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)