# BitShift Optimization

## Recommended Posts

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 on other sites

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

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

##### Share on other sites

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 on other sites

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

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

##### Share on other sites

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.

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:

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 on other sites

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.

;

```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 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.
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 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 on other sites

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 on other sites

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. 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 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.

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 on other sites

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

## Create an account

Register a new account

×

• Wiki

• Back

• #### Beta

• Git
• FAQ
• Our Picks
×
• Create New...