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) On 9/29/2016 at 9:05 AM, czardas said: Hmm division by 1 should be faster Expand 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 Reveal hidden contents 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 Reveal hidden contents 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 9/29/2016 at 10:27 AM, funkey said: Interesting thing is that AutoIt returns always an signed value. Is this a bug? Expand 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