Hex to Int conversion at runtime?
Monkey Forums/Monkey Programming/Hex to Int conversion at runtime?
| ||
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? |
| ||
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 |
| ||
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. |
| ||
Oops. Double post. |
| ||
@Floyd: Nice! Thanks! |
| ||
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 |
| ||
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 |
| ||
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. |
| ||
Using ascii codes instead of strings would be faster, IMO. |
| ||
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. |