Code archives/Miscellaneous/Val()
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Convert strings containing Hex, Binary or Floating/Integer Decimal values to a numeric value. | |||||
;**************************************************** ;** ;** Val() - Converts a numeric value in a string ;** to a decimal value. Strings can contain: ;** Integers ;** Floating point numbers ;** Hexadecimal ;** Binary ;** ;** For Hex values use any of these formats: ;** 0xFF $FF #FF ;** ;** For Binary use this format: ;** %11001010 ;** ;** NOTE: Because this function returns all values ;** as floating point, there is a limit to the ;** range of values it can handle accurately. ;** If you need integers that are larger than ;** 16777215 or smaller than -16777215 (12 bits) ;** then you should remove the # from the ;** function declaration and from the variable ;** Num# to get the fullest accuracy for large ;** integers. ;** ;** Courtesy of Barliesque :) ;** ;*************************************************** Local Value% Print Val("37") Print Val("3-7") Print Val("50.1") Print "0xFFFF = " + Int(Val("0xFFFF")) Print "#E5 = " + Val("#E5") Print "$FF = " + Val("$FF") Value = Val("%10010010") Print "%10010010 = " + Value WaitKey End ;**************************************************** Function Val#(StringNumeric$) Local Num# = 0 Local Hex1 = ((Left$(StringNumeric$,1)="#") Or (Left$(StringNumeric$,1)="$")) Local Hex2 = (Left$(StringNumeric$,2)="0x") Local Binary = (Left$(StringNumeric$,1)="%") Local i,c If Hex1 Or Hex2 StringNumeric$ = Upper(StringNumeric$) For i=(Hex1 + (Hex2 * 2) + 1) To Len(StringNumeric$) c = asc(Mid$(StringNumeric$,i,1)) Select true Case (c>=48 and c<=57) ;0 through 9 Num# = (Num# * 16) + c-48 Case (c>=65 and c<=70) ;A through F Num# = (Num# * 16) + c-55 Default Return Num# End Select Next Else If Binary For i=2 To Len(StringNumeric$) Select Mid$(StringNumeric$,i,1) Case "1" Num# = (Num# * 2) + 1 Case "0" Num# = (Num# * 2) Default Return Num# End Select Next Else Num# = StringNumeric$ EndIf EndIf Return Num# End Function |
Comments
| ||
Without looking through your code too much, however... You've got a big case statement which could be replaced with Instr("1234567890ABCDEF", mid(stringnumerics$,c,1)) Would return 0-16 which might make your life a little easier. |
| ||
Nah. Don't think that would change things for the better. I'm pretty sure the select/case structure is about as optimised as it's going to get. Other things could probably be optimised a teensy bit, like putting Mid$(StringNumeric$,c,1) into a variable, rather than calling that statement... well, twice actually. ...Nah, probably fine as it is. [EDIT] On second though, that select statement wasn't above a little bit of optimization. ;) |
| ||
There's really no way to make a single Blitz function that evaluates all types of numbers. If it returns an integer value then it can't handle anything after a decimal point, or extremely large values. If it returns a floating point number then it can't accurately represent an integer with too many digits. test$ = "1234567890" value = test Print value value = Val(test) Print value WaitKeyTry that with your Val() function, which returns a float. This is why Abs(), for example, is a built-in Blitz operator, not a function. Abs(1) is an integer while Abs(1.0) is a float. |
| ||
i made a simple function that converts strings such as '1', '1255' etc into ints by finding their length, then for each letter finding the int of the char's ascii, minus the ascii for 0, then multiplying it by 10^(its position from the length of the $), and then adding up that for each char. Its alot simpler, but of course only converts to int, although thenagain you could just divide anything after a decimal point by 10. |
| ||
@Floyd: Well you got me there. You're right. Frankly though, I'm not very concerned by that limitation for this function. It succesfully handles a very wide range of values and number bases in a single function. I designed it to extract information from a text file script for a game I'm working on. I want to include color values in the script, so the maximum value I need is 0xFFFFFF which appears to be the maximum value this function handles accurately. Phwew! Thank you for pointing out that limitation. It is good to know about. :) I'll add a note to the top of the code. @aab: I've used exactly that technique for handling Hex and Binary, but for decimal integers and floats that isn't necessary. Look more closely at how the function works and you'll see that decimal conversions are handled in just one statement: Num# = StringNumeric$If you make the function only return integer values, then this one line will also return the huge number Floyd tested with above. P.S. Following Rob Farley's comment above, I've just made a small optimization to the Select/Case structure in the Hex conversion. |
| ||
[ Val() by Barliesque ] It's all fascinating; I'm pretty sure there's a way to substantially improve the algorithm and code of the converter. One way to speed up the code would be to create a hex-lookup-table, will get back to you on this if I can think of the details. |
Code Archives Forum