Hex to Int conversion at runtime?

Monkey Forums/Monkey Programming/Hex to Int conversion at runtime?

ziggy(Posted 2012) [#1]
Is there any reason why hex conversion from string to int is not working?
Function Main()
	Print Int("$00AAFF00")
	Print Int("1235")
end

Looks weird that it only works with decimal notated integers, while we have a built-in syntax for hexadecimal notation. Maybe I'm doing something wrong?


ziggy(Posted 2012) [#2]
Does anybody know if this is a conversion bug?

EDIT: Any faster way than this (I'm skipping the $):
Function HexToInteger:Int(Hex:String)
	Local digit:Int, value:Int;
	For Local i:Int = 0 until Hex.Length;
		Select Hex[i]
			Case "0"[0]; digit = 0;
			Case "1"[0]; digit = 1;
			Case "2"[0]; digit = 2;
			Case "3"[0]; digit = 3;
			Case "4"[0]; digit = 4;
			Case "5"[0]; digit = 5;
			Case "6"[0]; digit = 6;
			Case "7"[0]; digit = 7;
			Case "8"[0]; digit = 8;
			Case "9"[0]; digit = 9;
			Case "A"[0], "a"[0]; digit = 10;
			Case "B"[0], "b"[0]; digit = 11;
			Case "C"[0], "c"[0]; digit = 12;
			Case "D"[0], "d"[0]; digit = 13;
			Case "E"[0], "e"[0]; digit = 14;
			Case "F"[0], "f"[0]; digit = 15;
			Default
				Error("unexpected character on hexadecimal literal.");
		End
		value+=digit * math.Pow(16, Hex.Length -i -1);
	Next
	Return value;
End



Floyd(Posted 2012) [#3]
You certainly don't want to use Pow on each digit. The faster way is to evaluate left to right, and multiply by 16 ( or shift left 4 bits ) at each step.

For example, the short hex string $375 has the decimal value ( ( 3*16 ) + 7)*16 + 5 which expands to 3*16*16 + 7*16 + 5.

You can find several Blitz3D/Max versions here.

By the way, this is a classic trick for evaluating polynomials. "hex to int" is just the particular case where the variable, such as x, is replaced by 16. It is called Horner's Method.


Floyd(Posted 2012) [#4]
Oops. Double post.


ziggy(Posted 2012) [#5]
@Floyd: Nice! Thanks!


ziggy(Posted 2012) [#6]
Ok, that's the final algo. It seems to work a lot faster, and it is simplier, wich is VERY nice.

Function HexToInteger:Int(Hex:String)
	Local digit:Int, value:Int;
	For Local i:Int = 0 until Hex.Length '-1;
		value*=16
		Select Hex[i]
			Case "0"[0]; digit = 0;
			Case "1"[0]; digit = 1;
			Case "2"[0]; digit = 2;
			Case "3"[0]; digit = 3;
			Case "4"[0]; digit = 4;
			Case "5"[0]; digit = 5;
			Case "6"[0]; digit = 6;
			Case "7"[0]; digit = 7;
			Case "8"[0]; digit = 8;
			Case "9"[0]; digit = 9;
			Case "A"[0], "a"[0]; digit = 10;
			Case "B"[0], "b"[0]; digit = 11;
			Case "C"[0], "c"[0]; digit = 12;
			Case "D"[0], "d"[0]; digit = 13;
			Case "E"[0], "e"[0]; digit = 14;
			Case "F"[0], "f"[0]; digit = 15;
			Default
				Error("unexpected character on hexadecimal literal.");
		End
		value = (value + digit) 
	Next
	Return value;
End



Samah(Posted 2012) [#7]
Is this faster? It just ignores invalid characters.
Function HexToInt:Int(hexstr:String)
	Local rv:Int = 0
	For Local i:Int = 0 Until hexstr.Length
		Local val:Int = hexstr[i]
		If val >= 48 And val <= 57 Then
			rv = rv * 16 + val - 48
		ElseIf val >= 65 And val <= 70 Then
			rv = rv * 16 + val - 55
		ElseIf val >= 97 And val <= 102 Then
			rv = rv * 16 + val - 87
		End
	Next
	Return rv
End



ziggy(Posted 2012) [#8]
I don't know if it is any faster as single char string literals accesed as integers, as instance: "F"[0] are converted to the counterpart integer constants at compile time, which at the same is a way to ensure you're using the proper target encoding for chars (just in case) But in the other hand, we don't have proper jump tables on the trans conversion (at least to c++) so I have no idea. anyway, it seems like both methods should be prety fast.


AdamRedwoods(Posted 2012) [#9]
Using ascii codes instead of strings would be faster, IMO.


ziggy(Posted 2012) [#10]
I'm not usin strings. "a"[0] is traslated to by trans to a plain old 65 integer constant. but the code is much more readable this way in my honest opinion.