Irios Posted September 28, 2016 Posted September 28, 2016 (edited) Searching and searching but I'm unable to find anyone with a proper solution. I see a lot of similar questions on this topic, but nothing that really provides what I'm looking for. Basically, I just want to convert a 8 byte hex value to unsigned integer. I.e. "FFFFFFFFFFFFFFFF". I'm working on SNMP opaque data types, and UINT64 values end up as signed INT64 when I use the internal processing of AutoIt. (Yeah, I know, this is because AutoIt always uses signed) Example ( I know you guys love example code snippets haha, so here's a two-liner): $sUINT64 = "FFFFFFFFFFFFFFFF" ConsoleWrite( Dec($sUINT64) ) -1 is not the result I want, of course. And I don't want "1.84467440737096e+019" either by adding manually in AutoIt. I need the decimal value (as a string) of 264 = 18,446,744,073,709,551,616 Anyone got a clever UDF for this? Or will I have to write one myself, adding and multiplying each hex value, and generating a text string as a result? I know how it can be done, I just hoped someone already had done it so I could steal their code. Edited October 1, 2016 by Irios solved! discord.me/autoit (unofficial)
funkey Posted September 28, 2016 Posted September 28, 2016 You could try the BigNum UDF Irios 1 Programming today is a race between software engineers striving tobuild bigger and better idiot-proof programs, and the Universetrying to produce bigger and better idiots.So far, the Universe is winning.
Tekk Posted September 28, 2016 Posted September 28, 2016 (edited) Local $aResult = DllCall("msvcrt.dll", "INT:cdecl", "sprintf", "STR", "", "STR", "%llu", "UINT64", -1) ConsoleWrite($aResult[1] & @CRLF) ;~ 18446744073709551615 Edited September 28, 2016 by Tekk I like to edit posts Irios 1
Irios Posted September 29, 2016 Author Posted September 29, 2016 (edited) Thank you both EDIT: Again, thanks @Tekk. It was horribly difficult to search for these things without really knowing what to look for. But with the DllCall example, it opened a whole new world to me, as I never realized you could do it that way. I even found ways to convert int to float now, and int64 to double. ( ) Edited September 29, 2016 by Irios discord.me/autoit (unofficial)
czardas Posted September 29, 2016 Posted September 29, 2016 (edited) A little trick I discovered. I think the fastest way to convert Int64 to double is to concatenate and execute. $iInt = 12345678901234567 $fFloat = Execute($iInt & '.0') MsgBox(0, "", $fFloat) Edit: Hmm division by 1 should be faster. $iInt = 12345678901234567 MsgBox(0, "", $iInt/1) Edited September 29, 2016 by czardas operator64 ArrayWorkshop
RTFC Posted September 29, 2016 Posted September 29, 2016 (edited) 18 minutes ago, czardas said: Hmm division by 1 should be faster Hmmm, multiplication by 1.0 should be faster than division (in FPU assembly at least). $iInt = 12345678901234567 MsgBox(0, "", $iInt*1.0) Edited September 29, 2016 by RTFC czardas 1 My Contributions and Wrappers Spoiler BitMaskSudokuSolver BuildPartitionTable CodeCrypter CodeScanner DigitalDisplay Eigen4AutoIt FAT Suite HighMem MetaCodeFileLibrary OSgrid Pool RdRand SecondDesktop SimulatedAnnealing Xbase I/O
funkey Posted September 29, 2016 Posted September 29, 2016 Interesting thing is that AutoIt returns always an signed value. Is this a bug? Global $s1 = "FFFFFFFFFFFFFFFF" Global $s2 = "FFFFFFFFFFFFFFF0" ConsoleWrite(_HexString2Uint64($s1) & @CRLF) ConsoleWrite(_HexString2Uint64($s2) & @CRLF) Func _HexString2Uint64($sHex) Local $b = Binary("0x" & $sHex) Local $tStruct = DllStructCreate("UINT64") Local $tStruct2 = DllStructCreate("byte[8]", DllStructGetPtr($tStruct)) DllStructSetData($tStruct2, 1, $b) Return DllStructGetData($tStruct, 1) EndFunc Programming today is a race between software engineers striving tobuild bigger and better idiot-proof programs, and the Universetrying to produce bigger and better idiots.So far, the Universe is winning.
czardas Posted September 29, 2016 Posted September 29, 2016 (edited) @RTFC Now I know why I went the root I did. Compare: MsgBox(0, "", '123456789012345678901234567890'*1.0) MsgBox(0, "", Execute('123456789012345678901234567890' & '.0')) The second method works for a few hundred digits and the first method quickly hits a brick wall. Edited September 29, 2016 by czardas operator64 ArrayWorkshop
RTFC Posted September 29, 2016 Posted September 29, 2016 Compare like with like: MsgBox(0, "", '123456789012345678901234567890.0'*1.0) MsgBox(0, "", Execute('123456789012345678901234567890' & '.0')) My Contributions and Wrappers Spoiler BitMaskSudokuSolver BuildPartitionTable CodeCrypter CodeScanner DigitalDisplay Eigen4AutoIt FAT Suite HighMem MetaCodeFileLibrary OSgrid Pool RdRand SecondDesktop SimulatedAnnealing Xbase I/O
czardas Posted September 29, 2016 Posted September 29, 2016 Yeah good point, I'll look into it. operator64 ArrayWorkshop
Irios Posted October 1, 2016 Author Posted October 1, 2016 (edited) On 29/09/2016 at 0:27 PM, funkey said: Interesting thing is that AutoIt returns always an signed value. Is this a bug? No, it's not a bug. AutoIt always uses signed int 64. That's what my original post was about: how to get around this limitation. I could not figure out a way to use DllCall, DllStructCreate, DllStructSetData, DllStructGetData. All the solutions/examples I found uses integers as paramteres, and won't work because AutoIt uses signed integers. Maybe someone has a way to do it? This is the solution I ended up using in my script as of today... Not very elegant, but it works. Can easily be extended beyond 64 bit if you need to. expandcollapse popup; v1.0 2016.09.29 Handles hex strings up to 16 characters in length i.e. "FFFFFFFFFFFFFFFF". Outputs a string representing the integer. ; Example: HexToUnsigned64("FFFFFFFFFFFFFFFF") Func HexToUnsigned64($_HexString) ; quick check to make sure it's a string, and 16 characters or shorter If (VarGetType($_HexString)<>"String") Or (StringLen($_HexString)>16) Then Return -1 ; Check to see if the value is within signed 64 bit. If so we just return the value immediately... ; We pad with zeros to get the correct length of 8 bytes (total 16 characters). ; Then we check to see if the the value is higher than 7FFFFFFFFFFFFFFFh (max positive value for signed 64 bit) If (StringLen($_HexString)<=16) Then $_HexString = StringFormat("%016s", $_HexString) If (Dec(StringLeft($_HexString,1))<8) Then Return Dec($_HexString) EndIf ; this is value of the leftmost 64th bit in an unsigned int 64. It must be a string, of course, ; as AutoIt only uses signed 64 bit integers. Local Const $_UINT64 = "9223372036854775808" ; we remove the highest bit so we can convert the other 63 bits internally $_iTmp = Dec(StringLeft($_HexString,1)) - 8 ; build a new 63bit integer string (without the highest bit) $_HexString = $_iTmp & StringRight($_HexString,15) $_HexString = String(Dec($_HexString)) ; padding input string with zeros so both become the same length (19 digits) $_HexString = StringFormat("%019s", $_HexString) Local $co = 0, $addReturn = "" ; starting at the far right side, max ops is 19 digits (number of digits in $_UINT64) For $A = 19 To 1 Step -1 ; building the return string, from the right-most side $addReturn = Mod( ( StringMid($_UINT64,$A,1) + StringMid($_HexString,$A,1) + $co), 10) & $addReturn ; getting the carry-over for the next loop $co = Int(( StringMid($_UINT64,$A,1) + StringMid($_HexString,$A,1) + $co ) / 10) Next If $co = 0 Then $co = "" Return $co & $addReturn ; all done, and returns the final value as a string EndFunc Example use: $sResult = HexToUnsigned64("FFFFFFFFFFFFFFFF") ConsoleWrite($sResult & @CRLF) ...the output is "18446744073709551615" Edited October 1, 2016 by Irios words and letters discord.me/autoit (unofficial)
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now