Skip to content

Instantly share code, notes, and snippets.

@KartikTalwar
Created February 10, 2013 19:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KartikTalwar/4750824 to your computer and use it in GitHub Desktop.
Save KartikTalwar/4750824 to your computer and use it in GitHub Desktop.
# 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