Jump to content

Bitwise operations with 64 bit integers


Recommended Posts

Hi guys,

Bitwise operations in Autoit is possible only till 32 bit integers, but sometimes WinAPI requires to process 64 bit vectors... so?

So you can use this little UDF to handle properly those integers!

Func _BitAND64($iValue1, $iValue2)
    If Not ((VarGetType($iValue1) = "Int64") Or (VarGetType($iValue2) = "Int64")) Then Return BitAND($iValue1, $iValue2)
    $iValue1 = __DecToBin64($iValue1)
    $iValue2 = __DecToBin64($iValue2)
    Local $aValueANDed[64], $i
    For $i = 0 To 63
        $aValueANDed[$i] = ($iValue1[$i] And $iValue2[$i]) ? 1 : 0
    Return __BinToDec64($aValueANDed)
EndFunc   ;==>_BitAND64

Func _BitOR64($iValue1, $iValue2)
    If Not ((VarGetType($iValue1) = "Int64") Or (VarGetType($iValue2) = "Int64")) Then Return BitOR($iValue1, $iValue2)
    $iValue1 = __DecToBin64($iValue1)
    $iValue2 = __DecToBin64($iValue2)
    Local $aValueORed[64], $i
    For $i = 0 To 63
        $aValueORed[$i] = ($iValue1[$i] Or $iValue2[$i]) ? 1 : 0
    Return __BinToDec64($aValueORed)
EndFunc   ;==>_BitOR64

Func _BitXOR64($iValue1, $iValue2)
    If Not ((VarGetType($iValue1) = "Int64") Or (VarGetType($iValue2) = "Int64")) Then Return BitXOR($iValue1, $iValue2)
    $iValue1 = __DecToBin64($iValue1)
    $iValue2 = __DecToBin64($iValue2)
    Local $aValueXORed[64], $i
    For $i = 0 To 63
        $aValueXORed[$i] = (($iValue1[$i] And (Not $iValue2[$i])) Or ((Not $iValue1[$i]) And $iValue2)) ? 1 : 0
    Return __BinToDec64($aValueXORed)
EndFunc   ;==>_BitXOR64

Func _BitNOT64($iValue)
    If Not (VarGetType($iValue) = "Int64") Then Return BitNOT($iValue)
    $iValue = __DecToBin64($iValue)
    For $i = 0 To 63
        $iValue[$i] = Not $iValue[$i]
    Return __BinToDec64($iValue)
EndFunc   ;==>_BitNOT64

Func __DecToBin64($iDec)
    Local $tDec = DllStructCreate("int64 num"), $aBin[64], $bBit, $i
    $tDec.num = $iDec
    For $i = 0 To 63
        $bBit = (Mod($tDec.num, 2) ? 1 : 0)
        $aBin[63 - $i] = $bBit
        $tDec.num = Floor($tDec.num / 2)
    Return $aBin
EndFunc   ;==>__DecToBin64

Func __BinToDec64($aBin)
    Local $tDec = DllStructCreate("int64 num"), $i
    If $aBin[0] Then $tDec.num += 0x8000000000000000 ;2^63 = 9223372036854775808, but for Autoit the world ends at 9223372036854775807 (2^63 - 1)
    For $i = 1 To 63
        If $aBin[$i] Then $tDec.num += 2 ^ (63 - $i)
    Return $tDec.num
EndFunc   ;==>__BinToDec64

If you are working with unsigned 64 bit integers and these functions return a negative value, don't worry, bitwise operations come out well, but Autoit manages all numbers as signed integers.

Link to comment
Share on other sites

  • 3 years later...

Since no-one has commented on these yet after so many years, and this is the first hit in Google when you search for 64-bit bitwise operations in AutoIt...

I'm sorry to report these functions are completely broken. All of them.

The reason for this is because your functions are mixing together data types Integer and Double in the arithmetic operations.

An example using ...

_BitAND64(0xFFFFFFFFFFFFFFFF, 0x1111111111111111)

... gives the incorrect result 0x1111111111112201 (correct result should be 0x1111111111111111).

Examples of operations from your UDF that will result in type Double:

$tDec.num = Floor($tDec.num / 2)
$tDec.num += 2 ^ (63 - $i)

Both the / and ^ operators are no-no if you want Integers. It doesn't matter if the result is a whole number, the type will still be Double.



As a solution, you need to split the values into hi DWORD and lo DWORD, perform the bitwise operation on the hi and lo DWORDs separately, and then simply merge the two DWORDS into a QWORD.

For example:

Func _BitAND64($_iValue1, $_iValue2)
    If (VarGetType($_iValue1)<>"Int64" And VarGetType($_iValue2)<>"Int64") Then Return Int(BitAND($_iValue1, $_iValue2), $NUMBER_64BIT)
    Local $_dHiDWORD1 = Dec(StringLeft(Hex($_iValue1, 16), 8))
    Local $_dLoDWORD1 = Int($_iValue1, $NUMBER_32BIT)
    Local $_dHiDWORD2 = Dec(StringLeft(Hex($_iValue2, 16), 8))
    Local $_dLoDWORD1 = Int($_iValue2, $NUMBER_32BIT)
    Return Dec(Hex(BitAND($_dHiDWORD1, $_dHiDWORD2), 8) & Hex(BitAND($_dLoDWORD1, $_dLoDWORD2), 8), $NUMBER_64BIT) 

This also ensures the return value is always a QWORD (Int64), as the name of the function implies.

As a bonus, by  getting rid of the use of DllStructCreate(), you speed up the function with maybe 50x times or more.

Edited by Irios

863nP4W.png discord.me/autoit  (unofficial)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Create New...