+ Reply to Thread
Results 1 to 11 of 11
Like Tree1Likes
  • 1 Post By Lynx3d

Thread: Better way of handling 64 bit numbers?

  1. #1
    Shield of Telara Adelea's Avatar
    Join Date
    Mar 2011
    Posts
    734

    Default Better way of handling 64 bit numbers?

    I am trying to map auction sold mails, with auction IDs.

    The mail contains a line :

    Auction Id: 382946706789106110

    However:

    /script print(string.format("%x", 382946706789106110))
    e84807

    Clearly not right !

    Using http://www.rapidtables.com/convert/n...mal-to-hex.htm we get:

    55080003A1201C0

    The auction that sold was o055080003A1201C0, so that matches up.

    So I need a way to convert the decimal in the mail, to the auction ID...

    Is there a better way than doing it manually?

    Code:
    local mxid = 382946706789106110
    
    local sout = ""
    
    while (mxid>0) do
    	local rmdr = mxid%65536
    	sout = string.format("%04x%s",r,sout)
    	mxid = (mxid -rmdr)/65536
    end
    
    print (string.format("%016s",sout))
    http://forums.riftgame.com/image.php?type=sigpic&userid=125779&dateline=13553  38065

  2. #2
    General of Telara
    Join Date
    Mar 2014
    Posts
    966

    Default

    I'm afraid not, Lua didn't support any integer type until the recently released 5.3 version. But Rift's interpreter is still based on 5.1 (not sure if it's LuaJit, if it is, it doesn't have the newer extension to deal with 64bit CTypes instead either)

    That means any numer is stored as double float, and only precise up to 2^53 = 9,007,199,254,740,992.

    Note that the correct hex representation of 382946706789106110 is NOT 0x055080003A1201C0, but 0x055080003A1201BE (at least that's what my gnome calculator says). This number requires 59 bits, and Lua (aswell as this online calculator) apparently rounds it up when converting to double, because the last 6 bits get lost.

    I haven't looked at the auction interface in Lua, but if that rounded number is really what it reports, the auction IDs are actually rather worthless...

  3. #3
    Shield of Telara Adelea's Avatar
    Join Date
    Mar 2011
    Posts
    734

    Default

    You are right...

    So that brings out the even more clunky, divide by two using strings and build by binary...

    Code:
    local mx = "382946706789106110"
    local sout = ""
    
    local evenodd = {
    	["0"] = {r=0, e=true},
    	["1"] = {r=0, e=false},
    	["2"] = {r=2, e=true},
    	["3"] = {r=2, e=false},
    	["4"] = {r=4, e=true},
    	["5"] = {r=4, e=false},
    	["6"] = {r=6, e=true},
    	["7"] = {r=6, e=false},
    	["8"] = {r=8, e=true},
    	["9"] = {r=8, e=false},
    }
    
    local bintohex = {
    	["0000"] = "0",	["0001"] = "1",	["0011"] = "3",	["0010"] = "2",
    	["0100"] = "4",	["0101"] = "5",	["0110"] = "6", ["0111"] = "7",
    	["1000"] = "8",	["1001"] = "9",	["1010"] = "A",	["1011"] = "B",
    	["1100"] = "C",	["1101"] = "D",	["1110"] = "E",	["1111"] = "F"
    }
    
    local last = "0"
    local cur = 0
    local divit = "0000"
    local numnew = ""
    local numhex = ""
    
    local bingrp = ""
    
    local cx = 0
    local ctr = 0
    
    local rx = true
    
    while rx do
    	numnew = ""
    	cx=0
    	ctr = ctr+1
    	local last = mx:sub(-1)
    	if evenodd[last].e then
    		divit = mx
    		bingrp = "0"..bingrp
    	else
    		divit = mx:sub(1,-2) .. evenodd[last].r
    		bingrp = "1"..bingrp
    	end
    	
    	if bingrp:len() == 4 then
    		numhex = bintohex[bingrp]..numhex
    		bingrp = ""
    	end
    	
    	for x=1, mx:len() do
    		cur = (cx*10)+tonumber(mx:sub(x,x))
    		if cur%2 == 1 then
    			cx=1
    		else
    			cx=0
    		end
    		cur = (cur-cx)/2
    		numnew = string.format("%s%d", numnew, cur)
    	end
    	if numnew:sub(1,1) == "0" then
    		mx = numnew:sub(2)
    	else
    		mx = numnew
    	end
    	if mx == "0" or mx == "" then
    		rx = false
    	end
    end
    
    if bingrp:len() > 0 then
    	bingrp = "000"..bingrp
    	bingrp = bingrp:sub(-4)
    	numhex = bintohex[bingrp]..numhex
    end
    
    print(numhex)
    55080003A1201BE

    This is slow, and messy... There has to be a better way!
    http://forums.riftgame.com/image.php?type=sigpic&userid=125779&dateline=13553  38065

  4. #4
    General of Telara
    Join Date
    Mar 2014
    Posts
    966

    Default

    There certainly are more concise ways to convert 64bit with 32bit math. Unfortunately I could only find a binary=>decimal conversion, but here is an implementation and explanation (see the "64-bit Conversion on a 32-bit Machine" section):
    http://homepage.cs.uiowa.edu/~jones/bcd/decimal.html

    If you actually read it you probably can do the math for the opposite conversion too xD

  5. #5
    Shield of Telara Adelea's Avatar
    Join Date
    Mar 2011
    Posts
    734

    Default

    The problem is, that doing any operations on the number dont give the right results.

    /print string.format("%x", 382946706789106110%256)
    c0

    So using modulo to find the last byte doesnt work.

    Doing a bitwise and with 0xFF to find the last 8 bits:

    /print string.format("%x", bit.band(382946706789106110, "0xFF"))
    7

    If I try and use a bitshift to divide by 256:

    /print string.format("%x", bit.rshift(382946706789106110,8))
    e848

    So it looks like most things that treat the value as a number dont work.

    Of courrse, the simplest solution would be for the auction mails to include the hex value of their ID rather than the decimal!
    http://forums.riftgame.com/image.php?type=sigpic&userid=125779&dateline=13553  38065

  6. #6
    General of Telara
    Join Date
    Mar 2014
    Posts
    966

    Default

    If you could store that huge number you wouldn't need any conversion code in the first place.

    You need to operate on a limited number of digits at once (from a string). The link I posted works on 4 hex digits (i.e. 16 bits) at once, and proves the maximum intermediate values don't surpass 32bit signed integer range.
    The lua version would look like this:

    Code:
    function hex2dec(n)
    	local d4, d3, d2, d1, d0, q;
    
    	d0 = tonumber(string.sub(n, -4), 16) or 0;
    	d1 = tonumber(string.sub(n, -8, -5), 16) or 0;
    	d2 = tonumber(string.sub(n, -12, -9), 16) or 0;
    	d3 = tonumber(string.sub(n, 1, -13), 16) or 0;
    
    	d0 = 656 * d3 + 7296 * d2 + 5536 * d1 + d0;
    	q = math.floor(d0 / 10000);
    	d0 = d0 % 10000;
    
    	d1 = q + 7671 * d3 + 9496 * d2 + 6 * d1;
    	q = math.floor(d1 / 10000);
    	d1 = d1 % 10000;
    
    	d2 = q + 4749 * d3 + 42 * d2;
    	q = math.floor(d2 / 10000);
    	d2 = d2 % 10000;
    
    	d3 = q + 281 * d3;
    	q = math.floor(d3 / 10000);
    	d3 = d3 % 10000;
    
    	d4 = q;
    
    	result = string.format("%4.4u", d4) .. string.format("%4.4u", d3) .. string.format("%4.4u", d2) ..
    			string.format("%4.4u", d1) .. string.format("%4.4u", d0)
    	return result
    end
    
    print(hex2dec("055080003A1201BE"))
    Though as said, I couldn't find a decimal->hexadecimal equivalent, and I'm not keen on doing the whole math for finding the required values.

  7. #7
    RIFT Community Ambassador the_real_seebs's Avatar
    Join Date
    Jan 2011
    Posts
    16,859

    Default

    You're overthinking it. Don't handle it as a number, handle it as a string.
    You can play WoW in any MMO. You don't have to play WoW in RIFT. Oh, and no, RIFT is not a WoW clone. Not having fun any more? Learn to play, noob! I don't speak for Riftui, but I moderate stuff there. Just came back? Welcome back! Here's what's changed. (Updated for 2.5!)

  8. #8
    General of Telara
    Join Date
    Mar 2014
    Posts
    966

    Default

    Quote Originally Posted by the_real_seebs View Post
    You're overthinking it. Don't handle it as a number, handle it as a string.
    Well I never suggestes anything different, but that doesn't change the fact that the Auction API uses hex strings in the format "o055080003A1201C0" as IDs/table indices (whatever the "o" prefix is for, it is not octal but hexadecimal), and the mail you get gives the decimal ID (a string too obviously), so you need to convert one to the other to compare them.

    Anyway, so far I can only offer a fast hex->decimal version, but the other way round would be nicer since the mail is the only place where you see the decimal value.

  9. #9
    General of Telara
    Join Date
    Mar 2014
    Posts
    966

    Default

    Okay, since Snooker matches take a while, I started to understand the algorithm to reverse it.
    I think I got it:

    Code:
    function dec2hex(n)
    	local d4, d3, d2, d1, d0, q;
    
    	d0 = tonumber(string.sub(n, -5)) or 0;
    	d1 = tonumber(string.sub(n, -10, -6)) or 0;
    	d2 = tonumber(string.sub(n, -15, -11)) or 0;
    	d3 = tonumber(string.sub(n, 1, -16)) or 0;
    
    	d0 = 0x8000 * d3 + 0xe400 * d2 + 0x86a0 * d1 + d0;
    	q = math.floor(d0 / 65536);
    	d0 = d0 % 65536;
    
    	d1 = q + 0xa4c6 * d3 + 0x540b * d2 + d1;
    	q = math.floor(d1 / 65536);
    	d1 = d1 % 65536;
    
    	d2 = q + 0x8D7e * d3 + 2 * d2;
    	q = math.floor(d2 / 65536);
    	d2 = d2 % 65536;
    
    	d3 = q + 3 * d3;
    	q = math.floor(d3 / 65536);
    	d3 = d3 % 65536;
    
    	d4 = q;
    
    	result = string.format("%4.4x", d4) .. string.format("%4.4x", d3) .. string.format("%4.4x", d2) ..
    			string.format("%4.4x", d1) .. string.format("%4.4x", d0)
    	return result
    end
    
    print(dec2hex("382946706789106110"))
    Note that the bitop library seems to be available in Rift, so you should be able to replace the division by 65536 by bit.rshift(x, 16), and the modulo by bit.band(x, 0xFFFF).
    Formatting may need some adjustments too, of curse.

  10. #10
    Shield of Telara Adelea's Avatar
    Join Date
    Mar 2011
    Posts
    734

    Default

    That is excellent - thank you!
    http://forums.riftgame.com/image.php?type=sigpic&userid=125779&dateline=13553  38065

  11. #11
    RIFT Community Ambassador the_real_seebs's Avatar
    Join Date
    Jan 2011
    Posts
    16,859

    Default

    Oh, I'd missed the thing about the decimal IDs in the mail. Whoops.

    Maybe worth pinging Zorba about that one.
    You can play WoW in any MMO. You don't have to play WoW in RIFT. Oh, and no, RIFT is not a WoW clone. Not having fun any more? Learn to play, noob! I don't speak for Riftui, but I moderate stuff there. Just came back? Welcome back! Here's what's changed. (Updated for 2.5!)

+ Reply to Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts