omegastripes
omegastripes

Reputation: 12602

Converting a number to normalized scientific notation

I'm trying to create a method converting a number to normalized scientific notation, here is the code that I'm using to calculate mantissa and exponent:

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

The problem I am facing is that this code gives wrong exponent value for some numbers, eg 1000, 10E+6, 10E+9, 10E+12, 10E+13, etc... Exactly for 1000 converted should be 1e3, but not 10e2. It's obvious that the same problem with numbers, whose logarithms are close to an integer value, like Log(1 - 5.55111512312578E-17) / Log(10), which result is 0, however 1 - 5.55111512312578E-17 less then 1, and result has to be negative.

How can I get rid of Double type imprecision, and get this code to work properly?

UPDATE

I assume the fastest and quite accurate method to calculate mantissa and exponent of number in normalized scientific notation may be as follows:

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

Or another one, based on @Bob's solution:

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

First one slightly faster. Both of them process exponent from -322 to 308, but return not normalized mantissa with powers of 10 less then -310. I have not tested them yet with numbers, whose logarithms are a marginally less but very close to an integer values.

UPDATE 2

I decided to attach here an extra Sub ConvEN(), allowing to represent a number in engineering notation with SI prefixes from "p" to "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

Upvotes: 0

Views: 1517

Answers (2)

Bob
Bob

Reputation: 1055

Try this:

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

Based on the comments, I re-wrote this my way, ignoring the structure from the 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

Upvotes: 0

Trigger
Trigger

Reputation: 11

Using strings rather than maths can help. Add your own error checking.

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)

Upvotes: 0

Related Questions