Jump to content
j0kky

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
    Next
    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
    Next
    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
    Next
    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]
    Next
    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)
    Next
    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)
    Next
    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.

Share this post


Link to post
Share on other sites
Posted (edited)

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) 
EndFunc

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

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Robinson1
      Okay it's about the style of the AutoIT Language. Concerning: 
      BitAND, BitOR, BitXOR, BitXOR, 
      BitShift, BitRotate
      That's a very simple but fundamental question:
       Why BitAND is not  infix?

      In most other common programming languages it is.
      Let's take JavaScript. Here I write:
      Result = Value & Mask
      But on AutoIT it's
      $Result = BitAND ( $Value , $Mask ) That's more the Lisp / prefix way.
      While the logical and is indeed infix
       
      $bIsEnable = $bIsGUI_chkEnabled and $bIsGUI_chkChecked
      So I wonder why it is like this.
      What is the Idea behind this language design decision?  

      Okay Autoit is a matured Language but yeah -  It's never to late for a change.
      Wasn't there ideas to unify it any way?
      So we also make the 'Bit' operations infix as well?
      ... while Just keeping the 'old' prefix version -for backwards compatibility - as well.

      UPDATE #1: Now I created a ticket for this:
      https://autoitscript.com/trac/autoit/ticket/3752

      Well to generalise/modulate It more I may bring it down to the Subject Verb Object  thing you have with language.
      "I go swimming" that's S-V-O or some infix.
      "Swimming I go". is O-S-V - postfix and sound much like yoda-style. While
      "go I swimming" is V-S-O - prefix and 'feels' more like kinda question.

      There is no right or wrong here - however personally I find infix is most appropriate here.
    • By iXX
      Hi!
      Looking for working code to  get full path of process  - both 32 & 64 bit.
      I tryed this bellow, but it works only for 32-bit processes, even if compiled for x64...
      Thanx for suggestions!
       
      Func _ProcessGetPath($vProcess) ;get the program path done by MrCreatoR Local $iPID = ProcessExists($vProcess) If NOT $iPID Then Return SetError(1, 0, -1) Local $aProc = DllCall('kernel32.dll', 'hwnd', 'OpenProcess', 'int', BitOR(0x0400, 0x0010), 'int', 0, 'int', $iPID) If NOT IsArray($aProc) OR NOT $aProc[0] Then Return SetError(2, 0, -1) Local $vStruct = DllStructCreate('int[1024]') Local $hPsapi_Dll = DllOpen('Psapi.dll') If $hPsapi_Dll = -1 Then $hPsapi_Dll = DllOpen(@SystemDir & '\Psapi.dll') If $hPsapi_Dll = -1 Then $hPsapi_Dll = DllOpen(@WindowsDir & '\Psapi.dll') If $hPsapi_Dll = -1 Then Return SetError(3, 0, '') DllCall($hPsapi_Dll, 'int', 'EnumProcessModules', _ 'hwnd', $aProc[0], _ 'ptr', DllStructGetPtr($vStruct), _ 'int', DllStructGetSize($vStruct), _ 'int_ptr', 0) Local $aRet = DllCall($hPsapi_Dll, 'int', 'GetModuleFileNameEx', _ 'hwnd', $aProc[0], _ 'int', DllStructGetData($vStruct, 1), _ 'str', '', _ 'int', 2048) DllClose($hPsapi_Dll) If NOT IsArray($aRet) OR StringLen($aRet[3]) = 0 Then Return SetError(4, 0, '') Return $aRet[3] EndFunc  
    • By 232showtime
      good day,
      Please I need a little help ive been trying to find where I got this magic number and I remember it was for Minimize, but I really dont remember where I got this. Last thing I remember i was reading the help file and saw this minize magic numbers, but I cant find it anymore, I dnt wnt to use this magic number anymore OMG! please help...
      here it is.
      Local $hAaSf = "C:\Main.xlsx" ;Main excel Local $iStateAsf = WinGetState($hAaSf) BitAND($iStateAsf, 16)  
    • By AutID
      Hello,

      I will put it as simple as possible
      Why this code runs perfectly on 32bit and it fails on 64bit?
      Local $hWND = WinGetProcess("[CLASS:LSS_app]") ConsoleWrite($hWND & @LF) Local $hModuleList = _WinAPI_EnumProcessModules($hWND) If @error Then ConsoleWrite("Error: " & @error & @LF) For $i = 0 To $hModuleList[0][0] - 1 ;~ If StringInStr($hModuleList[$i][1], "sysCap64.dll") Then ConsoleWrite($hModuleList[$i][0] & @LF) ;~ EndIf Next As the title says EnumProcessModules returns error 10 which I have no clue what it is.
      It must be something with autoit or my lack of coding because a similar code in C# will work like a charm on both x86 and x64
      Process[] Processes = Process.GetProcessesByName("winLSS64Cap"); Process nProcess = Processes[0]; Handle = OpenProcess(0x10, true, (uint)nProcess.Id); for(int i = 0; i < nProcess.Modules.Count; i++) { Console.WriteLine(nProcess.Modules[i].ModuleName); }  
    • By andygo
      hello,
       
      i have a script which can handle huge data.
      i feed it with textfiles, it reads each line into array, then compare the lines, do some string operations. this all happens in a for.to.next loop.
       
      the script only use 15% cpu of my 8core.amd
       
      can i force the script to use more cpuload an therefore being faster?
       
      would it make a speed difference to compile it as 64bit exe on 64bit systems?
       
      thank you for commemts :)
×
×
  • Create New...