• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Hexadecimals to Decimals

Status
Not open for further replies.

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
guys, I'm currently wondering in making converter from hexadecimals to decimals.. here is the code I made
JASS:
function X2I takes string hex returns integer
    local string hexas = "0123456789abcdef"
    local string sub1
    local string sub2
    local integer i = StringLength(hex)
    local integer i2
    local integer m = 0
    local integer int = 0
    
    loop
        exitwhen i == 0
        set i2 = 0
        set sub1 = SubString(hex, i-1, i)
        loop
            set i2 = i2 + 1
            set sub2 = SubString(hexas, i2-1, i2)
            if sub1 == sub2 or sub1 == StringCase(sub2, true)then
                set int = int + 15 * m * (i2-1) + i2 - 1
            endif
            exitwhen i2 == 16
        endloop
        set m = m + 1
        set i = i - 1
    endloop
    return int
endfunction

it's working perfectly but I think there must be simple way, or maybe not, not sure yet. please help me to make this converter perfect/optimized.. thnks :thumbs_up:

after finishing this one I'm also will make the converter from decimals to hexadecimals as well..

why I need this? my idea is to make gradient engine which able to produce text with gradient colors :thumbs_up:

Now, the converter from decimals to hexadecimals has done here is the code :)
JASS:
function I2X takes integer int returns string
    local string hexas = "0123456789abcdef"
    local string hex = ""
    local integer dev
    
    loop
        if int > 15 then
            set dev = int - (int / 16) * 16
            set int = int / 16
            set hex = SubString(hexas, dev, dev + 1) + hex
        else
            set hex = SubString(hexas, int, int + 1) + hex
            return hex
        endif
    endloop
    return hex
endfunction
 
Last edited:
Level 14
Joined
Dec 12, 2012
Messages
1,007
Hi,

it's working perfectly ...

Not really ;)
Your algorithm is wrong, for example for "ff2a" it outputs 1197 which is clearly wrong. Also having two nested loops is not necessary here as that only needs more performance.

Try something like this:

JASS:
// Converts a single hex digit to a decimal digit, returns -1 on error in debug mode
function HexDigit2Int takes string s returns integer
	local integer hex
	
	debug if StringLength(s) != 1 then
		debug return -1
	debug endif
	
	set s = StringCase(s, false)
	set hex = S2I(s)
	if s == "0" or hex != 0 then
		return hex
	elseif s == "a" then
		return 10
	elseif s == "b" then
		return 11
	elseif s == "c" then
		return 12
	elseif s == "d" then
		return 13
	elseif s == "e" then
		return 14
	elseif s == "f" then
		return 15
	endif
	return -1
endfunction

// Converts an arbitrary hex number into an integer
function Hex2Int takes string hex returns integer
	local integer length = StringLength(hex)
	local integer i = length
	local integer temp = 0
	local string digit
	loop
		set digit = SubString(hex, i - 1, i)
		set i = i - 1
		set temp = temp + HexDigit2Int(digit)*R2I(Pow(16.0, -1.0*(i - length + 1)))
		exitwhen i < 1
	endloop
	return temp
endfunction

And here an example:

JASS:
scope test initializer i
	private function i takes nothing returns nothing
		call BJDebugMsg(I2S(X2I("ff2a"))) // Displays 1197, which is wrong
		call BJDebugMsg(I2S(Hex2Int("ff2a"))) // Displays 65322, correct
	endfunction
endscope


Performance comparison:

The X2I function with the test number "ff2a" has an OP limit of 97 while the Hex2Int function has an OP limit of 591. Here you can see how expensive the nested loop is, the Hex2Int function is more than 6 times faster than your X2I function.
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
you are right, I have just notice it just now.. but the decimals to hexa is right I guess..

and I hope I don't need to use something like you have just mentioned
JASS:
function HexDigit2Int takes string s returns integer
    local integer hex
    
    debug if StringLength(s) != 1 then
        debug return -1
    debug endif
    
    set s = StringCase(s, false)
    set hex = S2I(s)
    if s == "0" or hex != 0 then
        return hex
    elseif s == "a" then
        return 10
    elseif s == "b" then
        return 11
    elseif s == "c" then
        return 12
    elseif s == "d" then
        return 13
    elseif s == "e" then
        return 14
    elseif s == "f" then
        return 15
    endif
    return -1
endfunction
D:


Gosh, my I2X is also wrong D:

// Displays 65332, correct must be // Displays 65322, correct >:D
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
and I hope I don't need to use something like you have just mentioned

What do you mean? You don't have to use anything, if you prefer having two nested loops and loose a lot performance you can of course stay with your function (once you fixed its bugs).

But then don't ask for improvements here -.-


EDIT:

// Displays 65332, correct must be // Displays 65322, correct >:D

Typo, corrected.
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
hey, chill, I'm not rejecting your suggestion, I was just hoping that I could do it in simple way without any other function (as example function to convert hexa digits to integer)

and
But then don't ask for improvements here -.-
I can't take such a response like that, just go away if you won't help, this place is not yours, understand?
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
hey, chill, I'm not rejecting your suggestion, I was just hoping that I could do it in simple way without any other function (as example function to convert hexa digits to integer)

Well the question is: what is simple for you? ;)

For me having an extra function here makes the code much cleaner and easier to read than having nested loops.

But this is only my opinion. If you prefer the nested loop, go for it. But the perfromance difference is quite huge (more than 600 %), so I wouldn't recommend it.
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
in my opinion simple is code with less lines :p
but you are right, yours is so much faster..

well, looks like I will delay this project, I see that working this using vJass will be so much easier, where I'm still zero at vJass D:

once again thanks and sorry, looking_for_help

I was escalated too fast D:
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
once again thanks and sorry, looking_for_help

I was escalated too fast D:

Hey, no problem. :)
The important thing is that your issue was solved.

in my opinion simple is code with less lines :p
but you are right, yours is so much faster..

Yes, less lines is also something very desireable, but here I guess this is the best tradeoff.

well, looks like I will delay this project, I see that working this using vJass will be so much easier, where I'm still zero at vJass D:

Ok, I thought you already know vJass? Or do you code in plain Jass? Then I would definitely recommend you to switch to vJass, it makes life a lot easier.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
I'm still plain Jasser, and Jass is a lot easier that GUI, so I can't imagine how easy is that vJass :D

I'm still learning structs :)

Thats good ;)

Btw, you know that you can use hex numbers directly in the World Editor, right?

So you can do for example:

JASS:
call BJDebugMsg(I2S(0xFF2A)) // Valid syntax, outputs 65322

So, if you want to do this with structs you could make it much easier for the user to pass values. The UI could look like this for example:

JASS:
function test takes nothing returns nothing
    local Hex hex = Hex.create(0xFF2A) // Create a hex number

    call BJDebugMsg(hex.toString()) // Would display "0xFF2A"
    call BJDebugMsg(I2S(hex.toDecimal())) // Would display 65322
endfunction

With this approach you would have many advantages:

  • Hex.create would only take integers, so users can't pass invalid values like they could with the X2I or the Int2Hex function (for example a typo like X2I("FF2S")). So no error checking would be necessary.
  • No X2I function would be neccessary because the value would be stored internaly as a normal integer number.
  • You could still perform all arithmetic operations with your hex-values. If you have your hex-values stored as string, you can't perform multiplication for example because "FF2A"*"A1" is not defined while 0xFF2A*0xA1 is.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Ok, take a look at this example:

JASS:
library HexaDecimals
	struct Hex
		private integer number

		static method create takes integer whichNumber returns thistype
			local thistype this = allocate()
			set this.number = whichNumber
			return this
		endmethod
		
		private method char2Hex takes integer c returns string
			if c >= 0 and c <= 9 then
				return I2S(c)
			elseif c == 10 then
				return "A"
			elseif c == 11 then
				return "B"
			elseif c == 12 then
				return "C"
			elseif c == 13 then
				return "D"
			elseif c == 14 then
				return "E"
			endif
			return "F"
		endmethod
		
		method toString takes nothing returns string
			local integer temp = number
			local integer tempOld = temp
			local integer rest
			local string s = ""
			loop
				set temp = temp/16
				set rest = tempOld - temp*16
				set tempOld = temp
				set s = char2Hex(rest) + s
				exitwhen temp == 0
			endloop
			return s
		endmethod
		
		method operator value takes nothing returns integer
			return number
		endmethod
		method operator value= takes integer whichNumber returns nothing
			set number = whichNumber
		endmethod
	endstruct
endlibrary

This would be an example implementation how you could do that. And now here an example usage:

JASS:
scope test initializer i
	private function i takes nothing returns nothing
		// Create the first hex value, which is 175 in decimal
		local Hex hex1 = Hex.create(0xAF) 

		// Create the second hex value, which is 45 in decimal
		local Hex hex2 = Hex.create(0x2D)

		// Compute 175 + 45 = 220 and store it into the variable hex1
		set hex1.value = hex1.value + hex2.value 
		
		// Outputs 0xDC which is 220 in hex
		call BJDebugMsg("0x" + hex1.toString() + " == " + I2S(hex1.value)) 
	endfunction
endscope

By doing so you only need internally to perform the conversion from decimal to hex in the method toString. The performance increases with this again clearly, raising the OP-limit of the method (toString) to 878 (nine times faster than the X2I function).

As the X2I function isn't required anymore as the hex value is stored internally as a normal decimal integer, you don't need to perform any conversions to get a decimal number from your hex numbers. You can directly use hex.value which has an OP limit of 11320 (which is about 116 times faster than your X2I function).

Finally you can now easily add/subtract/multiply/... your hex numbers as shown in the example. With strings you couldn't do that.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
I really don't see the point of using a class when its sole purpose is to have one function, and its only data is one integer that is fed into said function...sounds like a normal function and an argument to me.

Another thing is that you should consider is using a table/array (can't remember how Jass works with converting characters to integers) for the dec to hex conversion, but maybe this will be slower in Jass.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Yes, you don't really need a struct here, it was more because he said he is currently learning structs.

But still its much easier to use hex numbers directly than using something like function X2I takes string hex returns integer because you can directly use hex numbers in the editor.

So just make something like this:

JASS:
function test takes nothing returns nothing
    local integer hex1 = 0xAF
    local integer hex2 = 0x2D

    local integer hex3 = hex1 + hex2

    call BJDebugMsg(I2X(hex3))
endfunction

where I2X would be the toString method as a normal function.
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
JASS:
function test takes nothing returns nothing
    local integer hex1 = 0xAF
    local integer hex2 = 0x2D

    local integer hex3 = hex1 + hex2

    call BJDebugMsg(I2X(hex3))
endfunction
Idk that, that way can work to make a gradient engine :/ my logic said
why I need this? my idea is to make gradient engine which able to produce text with gradient colors :grin:

wait a second...
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
543
[…]
The X2I function with the test number "ff2a" has an OP limit of 97 while the Hex2Int function has an OP limit of 591. Here you can see how expensive the nested loop is, the Hex2Int function is more than 6 times faster than your X2I function.

I'm not implying you do, but don't confuse speed and op-limit. I can (and already did) write a function which is slower but has fewer micro-ops than some comparable function.

But yeah, most of the time there is a strong connection between these two.
 
Status
Not open for further replies.
Top