Created
February 10, 2013 19:55
-
-
Save KartikTalwar/4750824 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment