Sign in to follow this  
Followers 0
czardas

BitShift Optimization

13 posts in this topic

#1 ·  Posted (edited)

Can anyone get this function to go faster? Hex digits go in, and all the bits are shifted 1 step to the right - as fast as possible. The input string can be any length. The final input digit will always be even => 0, 2, 4, 6, 8, A, C or E.

;

$iTimer = TimerInit()
For $i = 1 To 10000
    BitShiftRight('FF777E3A9970F0B55FF99999999990F0F0065EA8546D8952') ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @LF)

; Hex digits only [0-9A-F]
Func BitShiftRight($dHex) ; Shift bits 1 step to the right.
    Local $aHexPart = StringRegExp($dHex, ".{1,7}", 3)
    Local $dShiftedHex = StringTrimLeft(Hex(BitShift(Dec($aHexPart[0]), 1), StringLen($aHexPart[0]) +1), 1), $iBound = UBound($aHexPart)
    If $iBound > 1 Then ; One time conditional.
        For $i = 1 To $iBound -2 ; Loop may or may not run.
            $dShiftedHex &= StringTrimLeft(Hex(BitShift(Dec(StringRight($aHexPart[$i -1], 1) & $aHexPart[$i]), 1)), 1)
        Next
        $dShiftedHex  &= StringTrimLeft(Hex(BitShift(Dec(StringRight($aHexPart[$iBound -2], 1) & $aHexPart[$iBound -1]), 1), StringLen($aHexPart[$iBound -1]) +1), 1)
    EndIf
    Return $dShiftedHex
EndFunc

;

I was hoping someone might be able to improve performance with a different method.

Edited by czardas

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

This code is although shorter but not faster:

Func Half($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,7}", 3), $i, $j, $sResult
    For $i = 0 To UBound($aHexPart) - 1
        $sResult &= StringRegExpReplace(Hex(Int(Dec($aHexPart[$i]) / 2)), "0*([\d.]+)", "$1")
    Next
    Return $sResult
EndFunc

StringRegExpReplace takes too much time.

#include <Array.au3>
$sHex = '7FBBBF1D4CB8785A' ; -> 3FDDDF8EA65C3C2D
$iRounds = 100000
$iTimer = TimerInit()
For $i = 1 To $iRounds
    BitShiftRight($sHex) ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @CRLF)
ConsoleWrite(BitShiftRight($sHex) & @CRLF & @CRLF)

$iTimer = TimerInit()
For $i = 1 To $iRounds
    Half($sHex) ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @CRLF)
ConsoleWrite(Half($sHex) & @CRLF)

; Hex digits only [0-9A-F]
Func BitShiftRight($dHex) ; Shift bits 1 step to the right.
    Local $aHexPart = StringRegExp($dHex, ".{1,7}", 3)
    Local $dShiftedHex = StringTrimLeft(Hex(BitShift(Dec('0' & $aHexPart[0]), 1), StringLen($aHexPart[0]) + 1), 1), $iBound = UBound($aHexPart)
    If $iBound > 1 Then ; One time conditional.
        For $i = 1 To $iBound - 2 ; Loop may or may not run.
            $dShiftedHex &= StringTrimLeft(Hex(BitShift(Dec(StringRight($aHexPart[$i - 1], 1) & $aHexPart[$i]), 1)), 1)
        Next
        $dShiftedHex &= StringTrimLeft(Hex(BitShift(Dec(StringRight($aHexPart[$iBound - 2], 1) & $aHexPart[$iBound - 1]), 1), StringLen($aHexPart[$iBound - 1]) + 1), 1)
    EndIf
    Return $dShiftedHex
EndFunc   ;==>BitShiftRight

Func Half($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,7}", 3), $i, $j, $sResult
    For $i = 0 To UBound($aHexPart) - 1
        $sResult &= StringRegExpReplace(Hex(Int(Dec($aHexPart[$i]) / 2)), "0*([\d.]+)", "$1") ;remove leading zeros from the result
    Next
    Return $sResult
EndFunc

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Thanks UEZ. BTW you forgot to carry any odd bits forward on subsequent loops after each division (7FBBBF1D4CB8785A ==> 3FDDDF8EA65C3C2D but your function gives 3FDDDF86A65C3C2D). That's partly why my code looks quite complicated. I was thinking a single regexp might be possible (perhaps for longer strings) or some dll call I don't know about. Using division might still be a good option.

Edited by czardas

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

I combined the two approaches. This gives a slight edge in performance so it helps a little. Thanks.

;

Func Half($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,7}", 3)
    Local $sResult = Hex(Int(Dec($aHexPart[0]) / 2), StringLen($aHexPart[0])), $iBound = UBound($aHexPart) -1
    If $iBound > 0 Then ; One time conditional.
        For $i = 1 To $iBound - 1 ; Loop may or may not run.
            $sResult &= Hex(Int(Dec($aHexPart[$i]) / 2 + 0x8000000 * Mod(Dec($aHexPart[$i -1]), 2)), 7)
        Next
        $sResult &= Hex(Int(Dec($aHexPart[$iBound]) / 2 + Dec(StringLeft('8000000', StringLen($aHexPart[$iBound]))) * Mod(Dec($aHexPart[$iBound -1]), 2)), StringLen($aHexPart[$iBound]))
    EndIf

    Return $sResult
EndFunc

;

Anyone got any more ideas?

Edited by czardas

Share this post


Link to post
Share on other sites

Indeed, I forgot to check out the carry. I can confirm that combined Half function is now faster.

Might be a good idea to look at BigNum UDF...

 

Btw, what do you want to achieve with so many calls? I mean you really need so many calls or is it just a optimization challenge?

Br,

UEZ

1 person likes this

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

The reason is I'm trying to develop a method of obfuscation. I noticed that the frequency of hex numbers [0-9] in the ascii codes (particularly for numbers and letters) is wildly out of proportion with the frequency of letters [A-F]. Shifting by one bit in binary changes the balance in favour of more letters. I came up with the plan to make the hex case sensitive but that requires the letters [A-F] to actually occur. :blink:

The hex for 'hello world' has a frequency ratio of 17 numbers to 5 letters. Random hex has a ratio of 5 : 3.

0x68656C6C6F20776F726C64

Shifting the bits to the left generally produces a lot more letters:

0xD0CAD8D8DE40EEDEE4D8C8

Incorporating case sensitive hex will tip the balance in some dependant way, but it's hardly worth pursuing if it introduces excessive latency.

Edited by czardas

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

I should have tried this earlier (ahem!): due to improvements made by trancexx some time ago, the hex can be parsed 12 characters at a time. I also found a bug in the earlier code. It's pretty obvious now. :doh:

;

Func Half($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,12}", 3)
    Local $sBatch = Dec($aHexPart[0], 2)
    Local $iBound = UBound($aHexPart) -1, $sResult = Hex(Int($sBatch / 2), StringLen($aHexPart[0])), $sCarry, $iLeftOver
    If $iBound > 0 Then ; One time conditional.
        $sCarry = $sBatch
        For $i = 1 To $iBound - 1 ; Loop may or may not run.
            $sBatch = Dec($aHexPart[$i], 2)
            $sResult &= Hex(Int($sBatch / 2 + 140737488355328 * Mod($sCarry, 2)), 12)
            $sCarry = $sBatch
        Next
        $iLeftOver = StringLen($aHexPart[$iBound])
        $sResult &= Hex(Int(Dec($aHexPart[$iBound], 2) / 2 + Dec(StringLeft('8000000000000', $iLeftOver), 2) * Mod($sCarry, 2)), $iLeftOver)
    EndIf

    Return $sResult
EndFunc

;

The reason for the 12 hexadecimal character limit is that Dec('8000000000000') produces a 16 digit integer and decimals need to remain within 15 digits for the method to work.

Edited by czardas

Share this post


Link to post
Share on other sites

How does code >using this compare to already posted solutions?

Granted it isn't full native yet it can be made self-contained by making the few opcodes inline and invoking it, à la Ward or others.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

Thanks a lot jchd. :) It looks like a nice library you created. I'll let you know how I get on tomorrow after I get time to play around with it.

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

You could speedup a bit using StringMid() instead of StringRegExp() to split the hex input string

$sHex = '123456789ABCDEF7FBBBF1D4CB8785A123456789ABCDEF7FBBBF1D4CB8785A123456789ABCDEF7FBBBF1D4CB8785A123456789ABCDEF7FBBBF1D4CB8785A'

$iTimer = TimerInit()
For $i = 1 To 10000
    Half($sHex)
Next
ConsoleWrite(TimerDiff($iTimer) & @TAB & "Half() by czardas. (this uses StringRegExp to split $sHex)" & @LF)
ConsoleWrite(Half($sHex) & @CRLF & @CRLF)

$iTimer = TimerInit()
For $i = 1 To 10000
    Half_mod($sHex)
Next
ConsoleWrite(TimerDiff($iTimer) & @TAB & "Half_mod() modified to use StringMid* instead of StringRegExp to split $sHex" & @LF)
ConsoleWrite(Half_mod($sHex) & @CRLF & @CRLF)

Func Half($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,12}", 3)
    Local $sBatch = Dec($aHexPart[0], 2)
    Local $iBound = UBound($aHexPart) - 1, $sResult = Hex(Int($sBatch / 2), StringLen($aHexPart[0])), $sCarry, $iLeftOver
    If $iBound > 0 Then ; One time conditional.
        $sCarry = $sBatch
        For $i = 1 To $iBound - 1 ; Loop may or may not run.
            $sBatch = Dec($aHexPart[$i], 2)
            $sResult &= Hex(Int($sBatch / 2 + 140737488355328 * Mod($sCarry, 2)), 12)
            $sCarry = $sBatch
        Next
        $iLeftOver = StringLen($aHexPart[$iBound])
        $sResult &= Hex(Int(Dec($aHexPart[$iBound], 2) / 2 + Dec(StringLeft('8000000000000', $iLeftOver), 2) * Mod($sCarry, 2)), $iLeftOver)
    EndIf
    Return $sResult
EndFunc   ;==>Half

Func Half_mod($sHex) ; it makes no use of StringRegExp
    Local $sBatch = Dec(StringMid($sHex, 1, 12), 2), $iLen = StringLen($sHex), $iLeftOver = Mod($iLen, 12), $sCarry
    Local $iBound = Int($iLen / 12), $sResult = Hex(Int($sBatch / 2), 12) ; ($iLeftOver * Not ($iBound)) + (12 * Not (Not ($iBound))))
    If $iBound Then ; One time conditional.
        $sCarry = $sBatch
        For $i = 13 To $iLen - $iLeftOver Step 12 ; Loop may or may not run.
            $sBatch = Dec(StringMid($sHex, $i, 12), 2)
            $sResult &= Hex(Int($sBatch / 2 + 140737488355328 * Mod($sCarry, 2)), 12)
            $sCarry = $sBatch
        Next
        $sResult &= Hex(Int(Dec(StringRight($sHex, $iLeftOver), 2) / 2 + Dec(StringLeft('8000000000000', $iLeftOver), 2) * Mod($sCarry, 2)), $iLeftOver)
    EndIf
    Return $sResult
EndFunc   ;==>Half_mod

edit:

p.s.

(this is just a marginal modification, not an improvement on the core of your function that is very fast as is.
I attempted a different approach also, but  achieved a bit slower speed of your, so I don't post here.
I also tried to use jchd's dll from post #8 by passing 32bit hex strings to the functions, but the overall performance is worst, I think because the time spent to setup the call to the dll vanify the 32bit approach)

Edited by Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

I'm afraid my first attempt to integrate jchd's functions failed, but I haven't tried the logical BitShift option yet. Although not a problem, there is no 64-bit multiply function which is needed in both cases. Actually I know where I went wrong. I'll try again.

Chimp: thanks for your suggestions. :) I think jchd's functions ought to give some improvement if implemeted correctly (using 14 or 15 character segments - at least one character must be held in reserve for the carry operation).

I thought RegExp was meant to be fast. :mellow: Anyway the following RegExp solution might look pretty, but it's the slowest method that I tried. The use of Execute() imposes a limit to the length of the input. The time taken to execute the expression also needs to be taken into consideration.

;

Func Half_Method_2($sString)
    Local $0=0, $1=1, $2=2, $3=3, $4=4, $5=5, $6=6, $7=7, $8=8, $9=9, $A=10, $B=11, $C=12, $D=13, $E=14, $F=15
    Local $aHx[32] = ['0','0','1','1','2','2','3','3','4','4','5','5','6','6','7','7','8','8','9','9','A','A','B','B','C','C','D','D','E','E','F','F']

    $sString = StringRegExpReplace($sString, '(?i)[13579BDF]','\0,')
    $sString = StringTrimRight(StringRegExpReplace($sString,'(?i)(,)*([0-9A-F])', '$aHx[$\2+16*("\1"=",")]&'), 1)
    Return Execute($sString)
EndFunc

;


UPDATE

Here's a working version using jchd's library. It has introduced quite a large regression.

;

Func Half_64a($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,14}", 3)
    Local $sBatch = Dec($aHexPart[0], 2)
    Local $iBound = UBound($aHexPart) -1, $sResult = Hex(Int(_Div($sBatch, 2)), StringLen($aHexPart[0])), $sCarry, $iLeftOver
    If $iBound > 0 Then ; One time conditional.
        $sCarry = $sBatch
        For $i = 1 To $iBound - 1 ; Loop may or may not run.
            $sBatch = Dec($aHexPart[$i], 2)
            $sResult &= Hex(Int(_BitOr(_Div($sBatch, 2), _MultByOne(Dec('800000000000000', 2), _Mod($sCarry, 2)))), 14)
            $sCarry = $sBatch
        Next
        $iLeftOver = StringLen($aHexPart[$iBound])
        $sResult &= Hex(Int(_BitOr(_Div(Dec($aHexPart[$iBound], 2), 2) ,_MultByOne(Dec(StringLeft('800000000000000', $iLeftOver), 2), _Mod($sCarry, 2)))), $iLeftOver)
    EndIf

    Return $sResult
EndFunc

Func _MultByOne($vHex, $iOne = 1)
    If $iOne = 0 Then $vHex = 0
    Return $vHex
EndFunc
Edited by czardas

Share this post


Link to post
Share on other sites

 

.... I think jchd's functions ought to give some improvement if implemeted correctly (using 14 or 15 character segments - at least one character must be held in reserve for the carry operation).

.....

 

in my attempt I elaborate all 16 (or 32) digits at a time. No need to reserve character for the carry, I just reserve 1 bit.

Unfortunately, this approach results slower. :ermm:

p.s.

it seems that your 64bit function gives wrong results as from the following test:

;;  Use DllOpen ... DllClose and pass the handle for heavy usage
Local $AddOnDllPath = "addons.dll" ; see post #8 to get this DLL
;
Local $nNrOfLoops = 1000 ; how many calls to the functions

$input = 'BC4DEF123456789ABC4ABC4DEF123456789ABC4DEF123456789DEF123456789ABC'

; ----------------------------------------------------------------------
$iTimer = TimerInit()
For $i = 1 To $nNrOfLoops
    Half($input) ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @TAB & "Half by czardas. (this uses StringRegExp)" & @LF)
ConsoleWrite(Half($input) & @CRLF & @CRLF)
; ----------------------------------------------------------------------
$iTimer = TimerInit()
For $i = 1 To $nNrOfLoops
    Half2($input) ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @TAB & "Half2 modified to use StringMid* instead of StringRegExp" & @LF)
ConsoleWrite(Half2($input) & @CRLF & @CRLF)
; ----------------------------------------------------------------------
$iTimer = TimerInit()
For $i = 1 To $nNrOfLoops
    HexShift_32bit($input) ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @TAB & "Chimp's 32 bit attempt" & @LF)
ConsoleWrite(HexShift_32bit($input) & @CRLF & @CRLF)
; ----------------------------------------------------------------------
$iTimer = TimerInit()
For $i = 1 To $nNrOfLoops
    HexShift_64bit($input) ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @TAB & "Chimp's 64 bit attempt" & @LF)
ConsoleWrite(HexShift_64bit($input) & @CRLF & @CRLF)
; ----------------------------------------------------------------------
$iTimer = TimerInit()
For $i = 1 To $nNrOfLoops
    Half_64a($input) ; Final digit must be even
Next
ConsoleWrite(TimerDiff($iTimer) & @TAB & "czardas 64 bit attempt" & @LF)
ConsoleWrite(Half_64a($input) & @CRLF & @CRLF)

; -------------------------------------------------------------------------------------------------
Func HexShift_32bit($dHex0) ; uses native Bit* functions 32 bit
    Local $dShiftedHex = "", $Carry, $nDecPart, $Mod = Mod(StringLen($dHex0), 8), $dHex = StringMid("0000000", Mod(StringLen($dHex0), 8), 7) & $dHex0, $strLen = StringLen($dHex)
    For $i = 1 To $strLen Step 8 ; loop al digits 8 at time
        $nDecPart = Dec(StringMid($dHex, $i, 8)) ; peek next group of 8 digits
        $dShiftedHex &= Hex(BitOR(BitRotate(BitAND($nDecPart, -2), -1, 'D'), $Carry))
        ;                   |     |         |
        ;                   |     |         BitAND($nDecPart, -2) ; turn off bit 1
        ;                   |     BitRotate(..)                   ; shift right & move bit 1 to bit 32 (this clear bit 32)
        ;                   BitOr( nn, $Carry)                    ; Turn bit 32 on or off according to $Carry (first shot is 0)
        ;
        $Carry = BitRotate(BitAND($nDecPart, 1), -1, 'D')      ; save the Carry to be used on next group of 8 digits
        ;        |         |
        ;        |         BitAND($nDecPart, 1)                ; turn off all bits but bit 1 (bit 1 remains unchanged)
        ;        BitRotate(.., -1, 'D')                        ; move bit 1 to bit 32
    Next
    If $Mod Then Return StringTrimLeft($dShiftedHex, 8 - $Mod) ; remove leading zeros (if any)
    Return $dShiftedHex
EndFunc   ;==>HexShift_32bit
; -------------------------------------------------------------------------------------------------

Func HexShift_64bit($dHex0) ; use 64 bit _Bit* functions from jchd DLL
    Local $dShiftedHex = "", $Carry = 0, $nDecPart = "", $Mod = Mod(StringLen($dHex0), 16), $dHex = StringMid("000000000000000", $Mod, 15) & $dHex0
    Local $strLen = StringLen($dHex), $ret1, $ret2, $ret3, $ret4, $ret5
    For $i = 1 To $strLen Step 16
        $nDecPart = Dec(StringMid($dHex, $i, 16))
        $ret1 = DllCall($AddOnDllPath, "uint64:cdecl", "BitAnd", "uint64", $nDecPart, "uint64", -2) ;    turn off bit 1
        $ret2 = DllCall($AddOnDllPath, "uint64:cdecl", "BitRotate", "uint64", $ret1[0], "int", 1) ;      rotate right (bit 1 goes to bit 32)
        $ret3 = DllCall($AddOnDllPath, "uint64:cdecl", "BitOr", "uint64", $ret2[0], "uint64", $Carry) ;  set bit 32 according to carry
        $dShiftedHex &= Hex($ret3[0])
        $ret4 = DllCall($AddOnDllPath, "uint64:cdecl", "BitAnd", "uint64", $nDecPart, "uint64", 1) ;     turn off all bits but bit 1 (bit 1 remains unchanged)
        $ret5 = DllCall($AddOnDllPath, "uint64:cdecl", "BitRotate", "uint64", $ret4[0], "int", 1) ;      bitRotate move bit 1 to bit 32, it will be the carry
        $Carry = $ret5[0]
    Next
    If $Mod Then Return StringTrimLeft($dShiftedHex, 16 - $Mod)
    Return $dShiftedHex
EndFunc   ;==>HexShift_64bit
; -------------------------------------------------------------------------------------------------
Func Half($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,12}", 3)
    ; _ArrayDisplay($aHexPart)
    Local $sBatch = Dec($aHexPart[0], 2)
    Local $iBound = UBound($aHexPart) - 1, $sResult = Hex(Int($sBatch / 2), StringLen($aHexPart[0])), $sCarry, $iLeftOver
    If $iBound > 0 Then ; One time conditional.
        $sCarry = $sBatch
        For $i = 1 To $iBound - 1 ; Loop may or may not run.
            $sBatch = Dec($aHexPart[$i], 2)
            $sResult &= Hex(Int($sBatch / 2 + 140737488355328 * Mod($sCarry, 2)), 12)
            $sCarry = $sBatch
        Next
        $iLeftOver = StringLen($aHexPart[$iBound])
        $sResult &= Hex(Int(Dec($aHexPart[$iBound], 2) / 2 + Dec(StringLeft('8000000000000', $iLeftOver), 2) * Mod($sCarry, 2)), $iLeftOver)
    EndIf
    Return $sResult
EndFunc   ;==>Half
; -------------------------------------------------------------------------------------------------
Func Half2($sHex) ; it makes NO use of StringRegExp
    Local $sBatch = Dec(StringMid($sHex, 1, 12), 2), $iLen = StringLen($sHex), $iLeftOver = Mod($iLen, 12), $sCarry
    Local $iBound = Int($iLen / 12), $sResult = Hex(Int($sBatch / 2), 12) ; ($iLeftOver * Not ($iBound)) + (12 * Not (Not ($iBound))))
    If $iBound > 0 Then ; One time conditional.
        $sCarry = $sBatch
        For $i = 13 To $iLen - $iLeftOver Step 12 ; Loop may or may not run.
            $sBatch = Dec(StringMid($sHex, $i, 12), 2)
            $sResult &= Hex(Int($sBatch / 2 + 140737488355328 * Mod($sCarry, 2)), 12)
            $sCarry = $sBatch
        Next
        ; $iLeftOver = Mod(StringLen($sHex), 12)
        $sResult &= Hex(Int(Dec(StringRight($sHex, $iLeftOver), 2) / 2 + Dec(StringLeft('8000000000000', $iLeftOver), 2) * Mod($sCarry, 2)), $iLeftOver)
    EndIf
    Return $sResult
EndFunc   ;==>Half2
; -------------------------------------------------------------------------------------------------
Func Half_64a($sHex)
    Local $aHexPart = StringRegExp($sHex, ".{1,14}", 3)
    Local $sBatch = Dec($aHexPart[0], 2)
    Local $iBound = UBound($aHexPart) -1, $sResult = Hex(Int(_Div($sBatch, 2)), StringLen($aHexPart[0])), $sCarry, $iLeftOver
    If $iBound > 0 Then ; One time conditional.
        $sCarry = $sBatch
        For $i = 1 To $iBound - 1 ; Loop may or may not run.
            $sBatch = Dec($aHexPart[$i], 2)
            $sResult &= Hex(Int(_BitOr(_Div($sBatch, 2), _MultByOne(Dec('800000000000000', 2), _Mod($sCarry, 2)))), 14)
            $sCarry = $sBatch
        Next
        $iLeftOver = StringLen($aHexPart[$iBound])
        $sResult &= Hex(Int(_BitOr(_Div(Dec($aHexPart[$iBound], 2), 2) ,_MultByOne(Dec(StringLeft('800000000000000', $iLeftOver), 2), _Mod($sCarry, 2)))), $iLeftOver)
    EndIf

    Return $sResult
EndFunc

Func _MultByOne($vHex, $iOne = 1)
    If $iOne = 0 Then $vHex = 0
    Return $vHex
EndFunc

; ------------------------
; following stuff by jchd
; -----------------------
;; Integer divide for 64-bit signed integers
Func _Div($iNumerator, $iDenominator)
    If IsInt($iNumerator) And IsInt($iDenominator) Then
        If $iDenominator = 0 Then Return(1 / 0) ;; make it behaves like the built-in / operator
        Local $ret = DllCall($AddOnDllPath, "int64:cdecl", "Div", "int64", $iNumerator, "int64", $iDenominator)
        If @error Then Return(SetError(@error, 0, ''))
        Return($ret[0])
    Else
        Return('')
    EndIf
EndFunc

;; Modulus for 64-bit signed integers
Func _Mod($iNumber, $iModulus)
    If IsInt($iNumber) And IsInt($iModulus) Then
        If $iModulus = 0 Then Return(1 / 0) ;; make it behaves like the built-in Mod() function
        Local $ret = DllCall($AddOnDllPath, "int64:cdecl", "Mod", "int64", $iNumber, "int64", $iModulus)
        If @error Then Return(SetError(@error, 0, ''))
        Return($ret[0])
    Else
        Return('')
    EndIf
EndFunc

;; Bitwise OR on 64-bit integers
Func _BitOr($uiA, $uiB)
    If IsInt($uiA) And IsInt($uiB) Then
        Local $ret = DllCall($AddOnDllPath, "uint64:cdecl", "BitOr", "uint64", $uiA, "uint64", $uiB)
        Return($ret[0])
    Else
        Return('')
    EndIf
EndFunc

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

No need to reserve character for the carry, I just reserve 1 bit.

The reason I did that was because I am using addition with the carry. That won't work with the sign bit included, so a whole nibble must be reserved for the original method to work correctly. With BitOR this is indeed unecessary.

it seems that your 64bit function gives wrong results as from the following test:

I didn't do extensive testing. I'll check this out later. Thanks again for testing.

Edited by czardas

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
Sign in to follow this  
Followers 0