Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I display 64 bit double number using VBScript on 32 Bit OS?

I have a device that contains 64 bit number (Double) parameters. I can read its Double parameters using Modbus protocol in two parts. So I split the 64 bit number to two 32 bit numbers using bitwise operation.

Example: 2289225.841082 (decimal) = 41417724-EBA8953E (hex)

You can check and test Hex conversation in the following site: http://babbage.cs.qc.edu/IEEE-754/ Copy 41417724EBA8953E and paste in "Value to analyze" edit-box in above site and press enter.

But after transferring the two 32 bit integers I can not merge it to original 64 bit number. I tried to use the CDbl and FormatNumber functions in VBScript, but it fails!

Dim nL, nH, fL, fH, f64 
nL = 1094809380 ' 4141 7724
nH = 3953694014 ' EBA8 953E
fL = CDbl($nL)
fH = CDbl($nH)
f64 = CDbl((fH * CDbl(2 ^ 32)) + CDbl(fL))
$strNum64 = FormatNumber( f64, 2)  

So, how can I display a 64 bit number using VBScript on a 32 bit OS?

like image 465
Behzad Ebrahimi Avatar asked Nov 13 '22 15:11

Behzad Ebrahimi


1 Answers

The "simple" answer to this, assuming pure VBScript, was to write a bignum add and multiply and then calculate the answer that way.

Using code from RosettaCode, I've created the following VeryLargeInteger class and a Hex64 function which says that 4702170486407730494 is the 64 bit decimal equivalent of 0x41417724EBA8953E

Option Explicit
Class VeryLongInteger
    'http://rosettacode.org/wiki/Long_Multiplication#Liberty_BASIC
    Public Function MULTIPLY(Str_A, Str_B)
        Dim signA, signB, sResult, Str_Shift, i, d, Str_T
        signA = 1
        If Left(Str_A,1) = "-" Then 
            Str_A = Mid(Str_A,2)
            signA = -1
        End If
        signB = 1
        If Left(Str_B,1) = "-" Then 
            Str_B = Mid(Str_B,2)
            signB = -1
        End If
        sResult = vbNullString
        Str_T = vbNullString
        Str_shift = vbNullString
        For i = Len(Str_A) To 1 Step -1
            d = CInt(Mid(Str_A,i,1))
            Str_T = MULTBYDIGIT(Str_B, d)
            sResult = ADD(sResult, Str_T & Str_shift)
            Str_shift = Str_shift & "0"
            'print d, Str_T, sResult 
        Next
        If signA * signB < 0 Then sResult = "-" + sResult
        'print sResult
        MULTIPLY = sResult
    End Function

    Private Function MULTBYDIGIT(Str_A, d)
        Dim sResult, carry, i, a, c
        'multiply Str_A by digit d
        sResult = vbNullString
        carry = 0
        For i = Len(Str_A) To 1 Step -1
            a = CInt(Mid(Str_A,i,1))
            c = a * d + carry
            carry = c \ 10
            c = c Mod 10
            'print a, c
            sResult = CStr(c) & sResult 
        Next
        If carry > 0 Then sResult = CStr(carry) & sResult
        'print sResult
        MULTBYDIGIT = sResult
    End Function

    Public Function ADD(Str_A, Str_B)
        Dim L, sResult, carry, i, a, b, c
        'add Str_A + Str_B, for now only positive
        l = MAX(Len(Str_A), Len(Str_B))
        Str_A=PAD(Str_A,l)
        Str_B=PAD(Str_B,l)
        sResult = vbNullString 'result
        carry = 0
        For i = l To 1 Step -1
            a = CInt(Mid(Str_A,i,1))
            b = CInt(Mid(Str_B,i,1))
            c = a + b + carry
            carry = Int(c/10)
            c = c Mod 10
            'print a, b, c
            sResult = CStr(c) & sResult
        Next
        If carry>0 Then sResult = CStr(carry) & sResult
        'print sResult
        ADD = sResult
    End Function

    Private Function Max(a,b)
        If a > b Then
            Max = a
        Else
            Max = b
        End If
    End Function

    Private Function pad(a,n)  'pad from right with 0 to length n
        Dim sResult
        sResult = a
        While Len(sResult) < n
            sResult = "0" & sResult
        Wend
        pad = sResult
    End Function
End Class

Function Hex64(sHex)
    Dim VLI
    Set VLI = New VeryLongInteger

    Dim Sixteen(16)
    Sixteen(0) = "1"
    Sixteen(1) = "16"
    Sixteen(2) = VLI.MULTIPLY(Sixteen(1),"16")
    Sixteen(3) = VLI.MULTIPLY(Sixteen(2),"16")
    Sixteen(4) = VLI.MULTIPLY(Sixteen(3),"16")
    Sixteen(5) = VLI.MULTIPLY(Sixteen(4),"16")
    Sixteen(6) = VLI.MULTIPLY(Sixteen(5),"16")
    Sixteen(7) = VLI.MULTIPLY(Sixteen(6),"16")
    Sixteen(8) = VLI.MULTIPLY(Sixteen(7),"16")
    Sixteen(9) = VLI.MULTIPLY(Sixteen(8),"16")
    Sixteen(10) = VLI.MULTIPLY(Sixteen(9),"16")
    Sixteen(11) = VLI.MULTIPLY(Sixteen(10),"16")
    Sixteen(12) = VLI.MULTIPLY(Sixteen(11),"16")
    Sixteen(13) = VLI.MULTIPLY(Sixteen(12),"16")
    Sixteen(14) = VLI.MULTIPLY(Sixteen(13),"16")
    Sixteen(15) = VLI.MULTIPLY(Sixteen(14),"16")

    Dim theAnswer, i, theDigit, theMultiplier, thePower, aPower
    theAnswer = "0"
    aPower = 0
    For i = Len(sHex) To 1 Step -1
        theDigit = UCase(Mid(sHex,i,1))
        theMultiplier = InStr("0123456789ABCDEF",theDigit)-1
        thePower = Sixteen(aPower)
        thePower = VLI.MULTIPLY(CStr(theMultiplier),thePower)
        theAnswer = VLI.ADD(theAnswer,thePower )
        aPower = aPower + 1
    Next
    Hex64 = theAnswer
End Function

WScript.Echo Hex64("41417724EBA8953E")

I'd like to say "enjoy" but it's been more than six months since the original posting, so you've likely found another solution. All the same, it was fun.

LATER

The other way to do the Hex64, if you want to avoid the precalculation of the powers of 16 is:

Function Hex64b(sHex)
    Dim VLI
    Set VLI = New VeryLongInteger       
    Dim theAnswer, i, theDigit, theMultiplier, thePower, aPower
    theAnswer = "0"
    thePower = "1"
    For i = Len(sHex) To 1 Step -1
        theDigit = UCase(Mid(sHex,i,1))
        theMultiplier = InStr("0123456789ABCDEF",theDigit)-1
        theAnswer = VLI.ADD(theAnswer,VLI.MULTIPLY(thePower,theMultiplier))
        thePower = VLI.MULTIPLY(thePower,"16")
    Next
    Hex64b = theAnswer
End Function
like image 147
bugmagnet Avatar answered Nov 15 '22 09:11

bugmagnet