How to parse a string to a float compatible with Numba `njit()`? - python
I have some Numba accelerated code in NoPython mode using numbaa.njit().
At some point I need to parse a str (or bytes) to get a float.
In pure Python, the way I would go about it is with float(), but that does not work:
import numba as nb
#nb.njit
def str2float(text):
return float(text)
str2float("1.2")
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<class 'float'>) found for signature:
>>> float(unicode_type)
while I would like it to produce a float with value 1.2.
The following questions are somewhat related:
this question discusses parsing to int (str/bytes-to-int)
this question discusses the opposite, i.e. the conversion of a float-to-str conversion
While this is not yet supported (as of July 2022), you can implement something manually.
Below are two versions, one for str and one for bytes.
In the process of solving the task I use a str/bytes-to-int which is used to parse str that include the exponential notation e.g. 1.0e-02 and -- potentially -- a trim() function to pre-process inputs surrounded by whitespaces ("C" whitespaces: " ", "\n", "\r", "\t", "\v").
Both are presented here and only used below.
From str
import math
import numba as nb
#nb.njit
def str2float_helper(text):
sep = ord(".")
c_min = ord("0")
c_max = ord("9")
n = len(text)
valid = n > 0
# determine sign
start = n - 1
stop = -1
sign = 1
if valid:
first = ord(text[0])
if first == ord("+"):
stop = 0
elif first == ord("-"):
sign = -1
stop = 0
# parse rest
sep_pos = 0
number = 0
j = 0
for i in range(start, stop, -1):
c = ord(text[i])
if c_min <= c <= c_max:
number += (c - c_min) * 10 ** j
j += 1
elif c == sep and sep_pos == 0:
sep_pos = j
else:
valid = False
break
return sign * number, sep_pos, valid
#nb.njit
def str2float(text):
if text == "nan" or text == "NAN" or text == "NaN":
return math.nan
exp_chars = b"eE"
exp_pos = -1
for exp_char in exp_chars:
for i, c in enumerate(text[::-1]):
c = ord(c)
if c == exp_char:
exp_pos = i
break
if exp_pos > -1:
break
if exp_pos > 0:
exp_number = str2int(text[-exp_pos:])
if exp_number is None:
exp_number = 0
number, sep_pos, valid = str2float_helper(text[:-exp_pos-1])
result = number / 10.0 ** (sep_pos - exp_number) if valid else None
else:
number, sep_pos, valid = str2float_helper(text)
result = number / 10.0 ** sep_pos if valid else None
return result
This should work similarly to float_() (defined below) which is a helper function that returns None instead of raising in case of parsing failure:
def float_(x):
try:
return float(x)
except ValueError:
return None
def is_close(x, y):
if x and not y or not x and y:
return False
else:
return x == y or math.isclose(x, y) or math.isnan(x) and math.isnan(y)
numbers = (
"", "NaN", "10", "32.1", "4123.43214e+05", "4123.43214E+05", "4123.43214e-05",
"-31", "-12.3", "-4123.43214e+05", "-4123.43214E+05", "-4123.43214e-05",
" 1321.432 \t ", "1+2", "1-2", "1e", "e1",
)
k = 24
for number in numbers:
print(f"{number!r:{k}} {float_(number)!s:{k}} {str2float(number)!s:{k}} {is_close(float_(number), str2float(number))}")
# '' None None True
# 'NaN' nan nan True
# '10' 10.0 10.0 True
# '32.1' 32.1 32.1 True
# '4123.43214e+05' 412343214.0 412343214.0 True
# '4123.43214E+05' 412343214.0 412343214.0 True
# '4123.43214e-05' 0.0412343214 0.0412343214 True
# '-31' -31.0 -31.0 True
# '-12.3' -12.3 -12.3 True
# '-4123.43214e+05' -412343214.0 -412343214.0 True
# '-4123.43214E+05' -412343214.0 -412343214.0 True
# '-4123.43214e-05' -0.0412343214 -0.0412343214 True
# ' 1321.432 \t ' 1321.432 None False
# '1+2' None None True
# '1-2' None None True
# '1e' None None True
# 'e1' None None True
# '1.1e-200' 1.1e-200 1.0999999999999995e-200 True
# '1.1e+200' 1.1e+200 1.1000000000000005e+200 True
(except for the trimming whitespaces part which can be added if needed).
Timewise, this is some 12x slower than pure Python:
%timeit -n 32 -r 32 [str2float(number) for number in numbers]
# 32 loops, best of 32: 80.3 µs per loop
%timeit -n 32 -r 32 [float_(number) for number in numbers]
# 32 loops, best of 32: 6.55 µs per loop
and hence only useful if this is needed as part of a more complex njit()-ed code.
From bytes
This is essentially a rewrite of the above to work with bytes (which typically only require skipping some ord(), because iterating bytes provides the integer representation directly) or defining a == operator because that is not available for bytes.
#nb.njit
def bytes2float_helper(text):
sep = ord(".")
c_min = ord("0")
c_max = ord("9")
n = len(text)
valid = n > 0
# determine sign
start = n - 1
stop = -1
sign = 1
if valid:
first = text[0]
if first == ord("+"):
stop = 0
elif first == ord("-"):
sign = -1
stop = 0
# parse rest
sep_pos = 0
number = 0
j = 0
for i in range(start, stop, -1):
c = text[i]
if c_min <= c <= c_max:
number += (c - c_min) * 10 ** j
j += 1
elif c == sep and sep_pos == 0:
sep_pos = j
else:
valid = False
break
return sign * number, sep_pos, valid
#nb.njit
def eqb(text_a, text_b):
len_a = len(text_a)
len_b = len(text_b)
if len_a == len_b:
for i in range(len_a):
if text_a[i] != text_b[i]:
return False
return True
else:
return False
#nb.njit
def bytes2float(text):
if eqb(text, b"nan") or eqb(text, b"NAN") or eqb(text, b"NaN"):
return math.nan
exp_chars = b"eE"
exp_pos = -1
for exp_char in exp_chars:
for i, c in enumerate(text[::-1]):
if c == exp_char:
exp_pos = i
break
if exp_pos > -1:
break
if exp_pos > 0:
exp_number = bytes2int(text[-exp_pos:])
if exp_number is None:
exp_number = 0
number, sep_pos, valid = bytes2float_helper(text[:-exp_pos-1])
result = number / 10.0 ** (sep_pos - exp_number) if valid else None
else:
number, sep_pos, valid = bytes2float_helper(text)
result = number / 10.0 ** sep_pos if valid else None
return result
The interesting bit it of this is that this has comparable speed (albeit marginally slower by some 15%) as the pure Python counterpart:
numbers = (
b"", b"NaN", b"10", b"32.1", b"4123.43214e+05", b"4123.43214E+05", b"4123.43214e-05",
b"-31", b"-12.3", b"-4123.43214e+05", b"-4123.43214E+05", b"-4123.43214e-05",
b" 1321.432 ", b"1+2", b"1-2", b"1e", b"e1", b"1.1e-200", b"1.1e+200",
)
k = 24
for number in numbers:
print(f"{number!s:{k}} {float_(number)!s:{k}} {bytes2float(number)!s:{k}} {is_close(float_(number), bytes2float(number))}")
# b'' None None True
# b'NaN' nan nan True
# b'10' 10.0 10.0 True
# b'32.1' 32.1 32.1 True
# b'4123.43214e+05' 412343214.0 412343214.0 True
# b'4123.43214E+05' 412343214.0 412343214.0 True
# b'4123.43214e-05' 0.0412343214 0.0412343214 True
# b'-31' -31.0 -31.0 True
# b'-12.3' -12.3 -12.3 True
# b'-4123.43214e+05' -412343214.0 -412343214.0 True
# b'-4123.43214E+05' -412343214.0 -412343214.0 True
# b'-4123.43214e-05' -0.0412343214 -0.0412343214 True
# b' 1321.432 ' 1321.432 None False
# b'1+2' None None True
# b'1-2' None None True
# b'1e' None None True
# b'e1' None None True
# b'1.1e-200' 1.1e-200 1.0999999999999995e-200 True
# b'1.1e+200' 1.1e+200 1.1000000000000005e+200 True
%timeit -n 32 -r 32 [bytes2float(number) for number in numbers]
# 32 loops, best of 32: 8.84 µs per loop
%timeit -n 32 -r 32 [float_(number) for number in numbers]
# 32 loops, best of 32: 7.66 µs per loop
Related
Python: Given a 2-D array, return True is every number in array is a power of two, 0, and greater than 2000. No imported libraries
Python: Given a 2-D array, create a function that will return True if every number in array is a power of two, 0 and greater than 200. No imported libraries. Ex: board = [[0,1,0,2],[0,0,2,4],[0,7,2001,0]] return False -- def is_data(board): col= len(board[0]) row= len(board) for c in range(col): for r in range(row): n= int(board[r][c]) if n > 2000: return False else: while isinstance(n, int) == True: if n % 2 != 1: if isinstance(n, float): return False break else: n = n//2 return True
floor division isn't powers-of-two. https://www.w3schools.com/python/trypython.asp?filename=demo_oper_floordiv def power_of_two( num ): while num > 1: num /= 2 if num == 1: return True else: return False print( power_of_two( 7 ) ) print( power_of_two( 92 ) ) print( power_of_two( 128 ) ) print( power_of_two( 4096 ) ) Output: False False True True
I need to make a EAN-13 number validity checker in Python2. I don't see why this doesn't work
inp = raw_input("Input a EAN-13 number.") aaa = False bbb = False if len(inp) == 13: bbb = True else: print "Error input" exit ean_number = int(inp) def ean13(value_1): mult_of_ten = 0 sum_of_digits = 0 done = False for z in len(value_1): if not z == 0: if z % 2 == 0: value_1[z] *= 3 elif not z % 2 == 0: value_1[z] *= 1 for a in len(value_1): sum_of_digits += value_1[a] if sum_of_digits % 10 == 0: result = 0 elif not sum_of_digits % 10 == 0: while done == False: mult_of_ten = sum_of_digits for d in True: mult_of_ten += d if sum_of_digits % 10 == 0: done == True result = mult_of_ten - sum_of_digits if result == value_1[12]: print "True" if bbb == True: ean13(ean_number) I really don't see why teacher can't help either. I need to make a EAN-13 number validity checker in Python2. I don't see why this doesn't work. Can anyone help?
I have made an EAN 13 Number Validity Checker in Python2. Hope it helps you out. # ean = '9780201379624' ean = raw_input("Input a EAN-13 number:\n") err = 0 even = 0 odd = 0 check_bit = ean[len(ean)-1]#get check bit(last bit) check_val = ean[:-1]#Get all vals except check bit if len(ean) != 13:#Check the input length print "Invalid EAN 13" else: for index,num in enumerate(check_val):#Gather Odd and Even Bits if index%2 == 0: even += int(num) else: odd += int(num) if ((3*odd)+even+int(check_bit)) % 10 == 0:# Check if the algorithm 3 * odd parity + even parity + check bit matches print "Valid EAN 13" else: print "Invalid EAN 13"
Continue while loop after return True
I am creating a function which returns True when a number(here X) is Prime. So I am checking whether the given number is evenly divisible by integers from 2 to X-1. But the while loop breaks when the check returns True. Help def is_prime(x): n = 2 if x < 2: return False elif x == 2: return True else: while True and n < x: if x % n == 0: return False else: n += 1 return True #--The loop is breaking here--
You code should look like this: def is_prime(x): n = 2 if x < 2: return False elif x == 2: return True else: while n < x: if x % n == 0: return False else: n += 1 # Put the return True after the loop return True print('{}: {}'.format(10, is_prime(10))) print('{}: {}'.format(11, is_prime(11))) print('{}: {}'.format(0, is_prime(0))) print('{}: {}'.format(1, is_prime(1))) print('{}: {}'.format(2, is_prime(2))) print('{}: {}'.format(113, is_prime(113))) Output: 10: False 11: True 0: False 1: False 2: True 113: True
Well You used return statment in loop, so it exited from method. You need to change the logic of this loop. Check here: Python Prime number checker
program who returns true or false whether a matrix is a magic square or not
I'm trying to make a program that returns a boolean whether a matrix is a magic square or not. I try to submit this code at my college's website, but it returns "Wrong Answer". I can't see what's wrong with it. Can you help me? def magico(xs): #print(soma(xs),soma2(xs),diag(xs)) if(soma(xs) == soma2(xs) == diag(xs) != -1 ): return True else: return False def soma(xs): sant = 0 s = 0 for i in range(len(xs)): if(s != sant): return -1 s = 0 for j in range(len(xs)): s = s + int(xs[i][j]) sant = s return s def soma2(xs): s = 0 sant = 0 for j in range(len(xs)): if(s != sant): return -1 s = 0 for i in range(len(xs)): s = s + int(xs[j][i]) sant = s return s def diag(xs): s = 0 for i in range(len(xs)): s = s + int(xs[i][i]) t = 0 for i in range(len(xs)): t = t + int(xs[i][len(xs) - 1 - i]) if(s == t): return s else: return -1
Pseudocode magic = true answer = sum(square)/n_rows(square) for r in rows(square): if sum(r) not equal to answer magic = false for c in columns(square): if sum(c) not equal to answer magic = false d1 = principal_diagonal(square) d2 = secondary_diagonal(square) if sum(d1) or sum(d2) not equal to answer magic = false display magic
You are not checking if the matrix is square, you are not checking if the numbers in the matrix are unique. Beyond that you have a serious coding issue: Your loops all end with sant = s They start with if(s != sant): But you have just made them equal...
Calculator which parses user input
import string # Strength of operations: # -> [] (brackets) # 6 -> ~ (negative) # 5 -> #, $, & (average, maximum, minimum) # 4 -> %, ! (modulo, factorial) # 3 -> ^ (power) # 2 -> *, / (multiplication, division) # 1 -> +, - (addition, subtraction) def BinaryOperation(exp, idx): """ Gets an expression and an index of an operator and returns a tuple with (first_value, operator, second_value). """ first_value = 0 second_value = 0 #Get first value idx2 = idx -1 if idx2 == 0: first_value = exp[idx2:idx] else: while (idx2 > 0) and (exp[idx2] in string.digits): idx2 -=1 if (exp[idx2] in ("-")) or (exp[idx2] in string.digits):#-5*3 first_value = exp[idx2:idx] else:#%5*3 first_value = exp[idx2+1:idx] #Get second value idx2 = idx +1 if exp[idx+1] not in string.digits: #If there is something like 1*+5, second_sign will be +. idx2 += 1 #idx2 will begin from the char after the sign. while (idx2 < len(exp)) and (exp[idx2] in string.digits): idx2 += 1 second_value = exp[idx+1:idx2] return (first_value, exp[idx], second_value) def UnaryOperation(exp, idx): """ Gets an expression and an index of an operator and returns a tuple with (operator, value). """ #Get value idx2 = idx+1 if exp[idx+1] not in string.digits: #If there is something like ~-5, second_sign will be -. idx2 += 1 #idx2 will begin from the char after the sign. while (idx2 < len(exp)) and (exp[idx2] in string.digits): idx2 +=1 return (exp[idx], exp[idx+1:idx2]) def Brackets(exp): idx = 0 while idx < len(exp): if exp[idx] == "[": #Brackets close_bracket = exp.find("]") if close_bracket == -1: raise Exception("Missing closing bracket.") exp_brackets = exp[idx+1:close_bracket] value = str(solve(exp_brackets)) exp = exp.replace("[" + exp_brackets + "]", value) idx = 0 #The len has been changed, scan again. idx += 1 return Level6(exp) def Level6(exp): idx = 0 while idx < len(exp): if exp[idx] in ("~"): #Negative sub_exp = UnaryOperation(exp, idx) value = ~int(sub_exp[1]) value = str(value) exp = exp.replace(''.join(sub_exp), value) idx = 0 #The len has been changed, scan again. idx += 1 return Level5(exp) def Level5(exp): idx = 0 while idx < len(exp): if exp[idx] in ("#", "$", "&"): #Average, Maximum and Minimum sub_exp = BinaryOperation(exp, idx) first_value = int(sub_exp[0]) second_value = int(sub_exp[2]) if sub_exp[1] == "#": value = (first_value + second_value)/2 if sub_exp[1] == "$": value = first_value if first_value > second_value else second_value if sub_exp[1] == "&": value = first_value if first_value < second_value else second_value value = str(value) exp = exp.replace(''.join(sub_exp), value) idx = 0 #The len has been changed, scan again. idx += 1 return Level4(exp) def Level4(exp): idx = 0 while idx < len(exp): if exp[idx] in ("%","!"): #Modulo and Factorial if exp[idx] == "%": sub_exp = BinaryOperation(exp, idx) value = int(sub_exp[0]) % int(sub_exp[2]) if exp[idx] == "!": sub_exp = UnaryOperation(exp, idx) value = reduce(lambda x,y:x*y, range(1, int(sub_exp[1])+1)) value = str(value) exp = exp.replace(''.join(sub_exp), value) idx = 0 #The len has been changed, scan again. idx += 1 return Level3(exp) def Level3(exp): idx = 0 while idx < len(exp): if exp[idx] in ("^"): #Power sub_exp = BinaryOperation(exp, idx) value = int(sub_exp[0]) ** int(sub_exp[2]) value = str(value) exp = exp.replace(''.join(sub_exp), value) idx = 0 #The len has been changed, scan again. idx += 1 return Level2(exp) def Level2(exp): idx = 0 while idx < len(exp): if exp[idx] in ("*", "/"): #Multiplication and Division sub_exp = BinaryOperation(exp, idx) if sub_exp[1] == "*": value = int(sub_exp[0]) * int(sub_exp[2]) if sub_exp[1] == "/": value = int(sub_exp[0]) / int(sub_exp[2]) value = str(value) exp = exp.replace(''.join(sub_exp), value) idx = 0 #The len has been changed, scan again. idx += 1 return Level1(exp) def Level1(exp): idx = 0 while idx < len(exp): if (exp[idx] in ("+", "-")) and (idx != 0): #Addition and Subtraction sub_exp = BinaryOperation(exp, idx) if sub_exp[1] == "+": value = int(sub_exp[0]) + int(sub_exp[2]) if sub_exp[1] == "-": value = int(sub_exp[0]) - int(sub_exp[2]) value = str(value) exp = exp.replace(''.join(sub_exp), value) idx = 0 #The len has been changed, scan again. idx += 1 return exp def solve(exp): exp = Brackets(exp) return float(exp) if "." in exp else int(exp) def remove_whitespace(exp): """ Gets a string and removes all whitespaces and tabs """ exp = exp.replace(" ", "") exp = exp.replace("\t", "") return exp while True: exp = raw_input("") exp = remove_whitespace(exp) print solve(exp) I have written this program after a lot of effort, and I was wondering about the efficiency of that solution and if it's neat. So my question is, how plain is this program and is there any better way to rewrite it?
just for the point. >>> eval(raw_input("input calculation: ")) input calculation: 1+1 2 >>> eval(raw_input("input calculation: ")) input calculation: (6*4^2) 26 >>> eval(raw_input("input calculation: ")) input calculation: (3/2.3)*4 5.2173913043478262 for an innocent program, you can use eval but you really shouldn't use it ever. its only real use is confusing people, and being a fun novelty if you write programs fro yourself and decide you want a calculator. there are many ways to write a calculator function. try some of these other answers: Python creating a calculator Basic calculator program in python python calculator program
If you want to check out some custom class-based evaluation engines in Python, these might help you: Expression Evaluator (version 1 with source) Math Evaluator (version 2 with source)
again = True answer = "" while again is True: try: expression = raw_input("Enter your expression: ") found = False oper = -1 operator1 = 0 operator2 = 0 while found==False: if (expression.find("+")>0 and expression.find("+")<len(expression)-1): found = True oper = expression.find("+") operator1 = float(expression[:oper]) operator2 = float(expression[oper+1:]) print "{} + {} = {}".format(operator1,operator2,operator1+operator2) elif(expression.find("-")>0 and expression.find("-")<len(expression)-1): found = True oper = expression.find("-") operator1 = float(expression[:oper]) operator2 = float(expression[oper+1:]) print "{} - {} = {}".format(operator1,operator2,operator1-operator2) elif(expression.find("*")>0 and expression.find("*")<len(expression)-1): found = True oper = expression.find("*") operator1 = float(expression[:oper]) operator2 = float(expression[oper+1:]) print "{} * {} = {}".format(operator1,operator2,operator1*operator2) elif(expression.find("/")>0 and expression.find("/")<len(expression)-1): found = True oper = expression.find("/") operator1 = float(expression[:oper]) operator2 = float(expression[oper+1:]) print "{} / {} = {}".format(operator1,operator2,operator1/operator2) else: oper = -1 found = False print "Incorrect expression, please try again" break again = False answer = raw_input("Try again?: ") if(answer == "y" or answer=="yes" or answer =="Y" or answer == "YES"): again = True else: again = False print "Thank you for playing! See you next time." break except: print "Failed, check your expression and try again"