# Function recreating the functionality of float() and int() in Python. # By Neil Fraser. Public Domain. 2012. def myFloat(input = 0.0): if type(input) != str: if type(input) == bool: return input and 1.0 or 0.0 if type(input) == float: return input if type(input) in (int, long): return input + 0.0 raise(TypeError('myFloat() argument must be a string or a number')) # Leading/trailing whitespace is ignored. Normalize to uppercase. input = input.strip().upper() # No known way to generate inf or nan without using float(). if input in ('INF', 'INFINITY', '+INF', '+INFINITY'): raise(NotImplementedError('myFloat() can\'t generate infinity')) elif input in ('-INF', '-INFINITY'): raise(NotImplementedError('myFloat() can\'t generate -infinity')) elif input in ('NAN', '+NAN', '-NAN'): raise(NotImplementedError('myFloat() can\'t generate NaN')) # Tokenize the input. negative = False integer = '' decimal = '' exp_negative = False exp_integer = '' # For maximum efficiency we should only store pointers to the start and end # positions of integer, decimal, and exp_integer, then slice them out in one # operation. However, for simplicity we'll just accumulate them character # by character as strings. state = -1 # Parse the input string with a finite state machine. # -1: Reading sign. # 0: Reading integer. # 1: Reading decimal. # 2: Reading exponent sign. # 3: Reading exponent. for c in input: if state == -1: state = 0 if c == '-': negative = True continue elif c == '+': continue # No sign; fall through to state 0. if state == 0: if c.isdigit(): integer += c elif c == '.': state = 1 elif c == 'E': state = 2 else: raise(ValueError('invalid integer for myFloat(): ' + input)) elif state == 1: if c.isdigit(): decimal += c elif c =='E': state = 2 else: raise(ValueError('invalid decimal for myFloat(): ' + input)) elif state == 2: if c == '+': state = 3 elif c == '-': exp_negative = True state = 3 elif c.isdigit(): exp_integer = c state = 3 else: raise(ValueError('invalid exponent for myFloat(): ' + input)) elif state == 3: if c.isdigit(): exp_integer += c else: raise(ValueError('invalid exponent integer for myFloat(): ' + input)) if (not (integer or decimal) or (state >= 2 and not exp_integer)): raise(ValueError('could not convert string to float: ' + input)) result = 0.0 if integer: result = myInt(integer) + 0.0 if decimal: decimal = myInt(decimal) / 10.0 ** len(decimal) result += decimal if exp_integer: exponent = myInt(exp_integer) if exp_negative: result /= 10 ** exponent else: result *= 10 ** exponent if negative: result = -result return result def myInt(input = 0, *args): if len(args) > 1: raise(TypeError('int() takes at most 2 arguments (' + str(len(args) + 1) + ' given)')) if len(args) == 1: base = args[0] if type(base) == bool: base = base and 1 or 0 if type(base) == float: raise(TypeError('integer argument expected, got float')) if type(base) != int: raise(TypeError('an integer is required')) if type(input) != str: raise(TypeError('myInt() can\'t convert non-string with explicit base')) if base != 0 and (base < 2 or base > 36): raise(ValueError('myInt() base must be >= 2 and <= 36')) else: base = 10 orig_base = str(base) if type(input) == int: return input if type(input) == bool: return input and 1 or 0 if type(input) == long: input = str(input) if type(input) == float: # Remove the float's decimal. input = str(input) input = input[:input.index('.')] if type(input) != str: raise(TypeError('myInt() argument must be a string or a number, ' + 'not \'' + str(type(input)) + '\'')) # Leading/trailing whitespace is ignored. Normalize to uppercase. input = input.strip() orig_input = input input = input.upper() # Handle any leading sign. negative = False if input.startswith('-'): negative = True input = input[1:] elif input.startswith('+'): input = input[1:] if not input: raise(ValueError('empty literal for myInt()')) # Determine assumed base. if base == 0: if input.startswith('0B'): base = 2 input = input[2:] elif input.startswith('0X'): base = 16 input = input[2:] elif input.startswith('0O'): base = 8 input = input[2:] elif input.startswith('0'): base = 8 input = input[1:] else: base = 10 integer = 0 multiplier = 1 for c in range(len(input) - 1, -1, -1): n = ord(input[c]) if 48 <= n <= 57: # 0-9 n -= 48 elif 65 <= n <= 90: # A-Z n -= (65 - 10) else: n = 99 if n >= base: raise(ValueError('invalid literal for myInt() with base ' + orig_base + ': \'' + orig_input + '\'')) integer += n * multiplier multiplier *= base if negative: integer = -integer return integer