This is for a school project. I need to create a function using recursion to convert an integer to binary string. It must be a str returned, not an int. The base case is n==0, and then 0 would need to be returned. There must be a base case like this, but this is where I think I am getting the extra 0 from (I could be wrong). I am using Python 3.6 with the IDLE and the shell to execute it.
The function works just fine, expect for this additional zero that I need gone.
Here is my function, dtobr:
def dtobr(n):
"""
(int) -> (str)
This function has the parameter n, which is a non-negative integer,
and it will return the string of 0/1's
which is the binary representation of n. No side effects.
Returns bianry string as mentioned. This is like the function
dtob (decimal to bianary) but this is using recursion.
Examples:
>>> dtob(27)
'11011'
>>> dtob(0)
'0'
>>> dtob(1)
'1'
>>> dtob(2)
'10'
"""
if n == 0:
return str(0)
return dtobr(n // 2) + str(n % 2)
This came from the function I already wrote which converted it just fine, but without recursion. For reference, I will include this code as well, but this is not what I need for this project, and there are no errors with this:
def dtob(n):
"""
(int) -> (str)
This function has the parameter n, which is a non-negative integer,
and it will return the string of 0/1's
which is the binary representation of n. No side effects.
Returns bianry string as mentioned.
Examples:
>>> dtob(27)
'11011'
>>> dtob(0)
'0'
>>> dtob(1)
'1'
>>> dtob(2)
'10'
"""
string = ""
if n == 0:
return str(0)
while n > 0:
remainder = n % 2
string = str(remainder) + string
n = n // 2
Hopefully someone can help me get ride of that additional left hand zero. Thanks!
You need to change the condition to recursively handle both the n // 2 and n % 2:
if n <= 1:
return str(n) # per #pault's suggestion, only needed str(n) instead of str(n % 2)
else:
return dtobr(n // 2) + dtobr(n % 2)
Test case:
for i in [0, 1, 2, 27]:
print(dtobr(i))
# 0
# 1
# 10
# 11011
FYI you can easily convert to binary format like so:
'{0:b}'.format(x) # where x is your number
Since there is already an answer that points and resolves the issue with recursive way, lets see some interesting ways to achieve same goal.
Lets define a generator that will give us iterative way of getting binary numbers.
def to_binary(n):
if n == 0: yield "0"
while n > 0:
yield str(n % 2)
n = n / 2
Then you can use this iterable to get decimal to binary conversion in multiple ways.
Example 1.
reduce function is used to concatenate chars received from to_binary iterable (generator).
from functools import reduce
def to_binary(n):
if n == 0: yield "0"
while n > 0:
yield str(n % 2)
n = n / 2
print reduce(lambda x, y: x+y, to_binary(0)) # 0
print reduce(lambda x, y: x+y, to_binary(15)) # 1111
print reduce(lambda x, y: x+y, to_binary(15)) # 11011
Example 2.
join takes iterable, unrolls it and joins them by ''
def to_binary(n):
if n == 0: yield "0"
while n > 0:
yield str(n % 2)
n = n / 2
print ''.join(to_binary(0)) # 0
print ''.join(to_binary(1)) # 1
print ''.join(to_binary(15)) # 1111
print ''.join(to_binary(27)) # 11011
I am currently developping a python program to tranform a symbolic expression computed by sympy into a numpy array containing all the numerical values. I instantiate the symbolic expression with the sympy.lambdify function.
Some of the symbolic expressions contain Bessel functions, and I pass scipy.special.jv/jy etc. as parameters in the lambdify function. Here is the single code (appart from the program) :
m = Symbol('m')
expr= -1.06048319593874*(-(3.14159265358979*m*besselj(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*besselj(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I)))*bessely(27.9937791601866*m, 6.81776274795262*sqrt(-I))/(3.14159265358979*m*bessely(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*bessely(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I))) + besselj(27.9937791601866*m, 6.81776274795262*sqrt(-I)))*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m
nm = 5
vm = arange(nm) +1
bessel = {'besselj':jv,'besselk':kv,'besseli':iv,'bessely':yv}
libraries = [bessel, "numpy"]
result = lambdify(m, expr, modules=libraries)(vm)
In[1] : result
Out[1]:
array([ -7.51212638e-030 -3.22606326e-030j,
4.81143544e-046 +1.04405860e-046j,
1.97977798e-097 +3.02047228e-098j,
3.84986092e-124 +4.73598141e-125j,
1.12934434e-181 +1.21145535e-182j])
The result is as I expected : a 5 rows 1-d array with each integer value of the symbol m.
The problem is when I try to implement it in the program. Here is the implementation :
expr = list_symbolic_expr[index]
vcm = arange(Dim_col[0]) +1 #Dim_col = list of integer range values to instantiate
m = Symbol(str(Var_col[0])) #Var_col = list of symbolic integer parameters
print expr, m
smat = lambdify(m, expr, modules=libraries)(vcm)
Here is the error when using scipy.special bessel functions :
In [2]: run Get_System_Num
Out [2]:
-1.06048319593874*(-(3.14159265358979*m*besselj(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*besselj(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I)))*bessely(27.9937791601866*m, 6.81776274795262*sqrt(-I))/(3.14159265358979*m*bessely(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*bessely(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I))) + besselj(27.9937791601866*m, 6.81776274795262*sqrt(-I)))*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m m
File "Numeric\Get_System_Num.py", line 183, in get_Mat
smat = lambdify(m, expr, modules=libraries)(vcm)
File "<string>", line 1, in <lambda>
TypeError: ufunc 'jv' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
Here is the error when using sympy.special bessel functions :
File "Numeric\Get_System_Num.py", line 183, in get_Mat
smat = lambdify(m, expr, modules=libraries)(vcm)
File "<string>", line 1, in <lambda>
File "C:\Users\Emile\Anaconda2\lib\site-packages\sympy\core\function.py", line 375, in __new__
result = super(Function, cls).__new__(cls, *args, **options)
File "C:\Users\Emile\Anaconda2\lib\site-packages\sympy\core\function.py", line 199, in __new__
evaluated = cls.eval(*args)
File "C:\Users\Emile\Anaconda2\lib\site-packages\sympy\functions\special\bessel.py", line 161, in eval
if nu.is_integer:
AttributeError: 'numpy.ndarray' object has no attribute 'is_integer'
It seems that lambdify cannot interprete properly the input value in the bessel function in the program code (wether it is with scipy or sympy bessel functions), as the input value seems to be an array object, while it is not a problem in the single code. Yet I do not see the difference between them.
Thank you for reading this, and I hope someone may help me on this topic. Please tell me if more information are needed to illustrate this problem.
--Edit 1--
I have kept on searching the problem, and even when I try to lambdify this simple expression : 17469169.5935065*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m, with "numpy" as module argument, it gives : 'float' object has no attribute 'sin'
I have also tried the packaged module 'numexpr' without success, as it stops on this other expression : 0.058**(46.6321243523316*k), saying :
File "C:\Users\Emile\Anaconda2\lib\site-packages\numexpr\necompiler.py", line 756, in evaluate
signature = [(name, getType(arg)) for (name, arg) in zip(names, arguments)]
File "C:\Users\Emile\Anaconda2\lib\site-packages\numexpr\necompiler.py", line 654, in getType
raise ValueError("unknown type %s" % a.dtype.name)
ValueError: unknown type object
So I really don't know the nature of this problem, and I can't even track it as the exception raised comes from inside sympy and I don't know how to put flags in sympy functions.
--Edit 2--
Here is the body of the Get_System_Num class : first the imports, then I also import the data from the symbolic project, meaning : each symbolic coefficient that I want to instantiate (listed in Mat_Num) ; the symbols to instantiate (listed in "list_Var') for each coefficient and depending on the rows and columns ; the size and the position of the instantiated matrix in the real big matrix (listed in list_Dim). As those lists are symbolic at the beginning I need to substitute symbols with real values that I put in Pr_Num <=> numerical project, and I do it in the sub_system_num method.
from numpy import diag, zeros, concatenate, arange, meshgrid, array
from scipy.special import jv,kv,iv,yv
from sympy import srepr, Matrix, lambdify, Symbol
from Numeric.Sub_System_Num import Sub_System_Num
class Get_System_Num :
#Calling constructor
def __init__(self, Pr_Num) :
#Assigning inputs values to local values
self.Pr_Num = Pr_Num
self.Pr_Symb = Pr_Num.Pr_Symb
#Load data from Pr_Symb
self.Mat_Num_Index = self.Pr_Symb.Mat_Num_Index
#Subs symbols with numeric values
print "Substitute symbols with real values..."
self.Sub_System_Num = Sub_System_Num(self)
#Gathering the results
self.Mat_Num = self.Sub_System_Num.Mat_Num
self.Mat_Size = self.Sub_System_Num.Mat_Size
self.list_Index = self.Sub_System_Num.list_Index
self.list_Var_row = self.Sub_System_Num.list_Var.col(0)
self.list_Dim_row = self.Sub_System_Num.list_Dim.col(0)
self.list_Var_col = self.Sub_System_Num.list_Var.col(1)
self.list_Dim_col = self.Sub_System_Num.list_Dim.col(1)
self.count = 0
print "Compute numerical matrix..."
self.Mat = self.get_Mat()
Here is the method to fill the numerical Matrix. I only put the case where there is only one variable to instantiate for both row and column. It's one case among 9 (3²) possible, as each row and columns have either 0,1 or 2 variables to instantiate. About the if srepr(coeff).__contains__(srepr(Var_row[0])) : this checks if the variable is really contained in the expr, and if not I duplicate manually the coeff. As expressions are previousvly computed symbolically, sometimes sympy may simplify them so that the variable is not here anymore.
def get_Mat(self) :
bessel = {'besselj':jv,'besselk':kv,'besseli':iv,'bessely':yv}
libraries = [bessel, 'numpy']
Mat = zeros((self.Mat_Size[0], self.Mat_Size[0]), dtype=complex)
for index in range(0, self.Mat_Num_Index.__len__()) :
Nb_row = self.list_Index[self.Mat_Num_Index[index][0], 0]
Nb_col = self.list_Index[self.Mat_Num_Index[index][1], 1]
Pos_row = self.list_Index[self.Mat_Num_Index[index][0], 2]
Pos_col = self.list_Index[self.Mat_Num_Index[index][1], 3]
Var_row = self.list_Var_row[self.Mat_Num_Index[index][0]]
Var_col = self.list_Var_col[self.Mat_Num_Index[index][1]]
Dim_row = self.list_Dim_row[self.Mat_Num_Index[index][0]]
Dim_col = self.list_Dim_col[self.Mat_Num_Index[index][1]]
coeff = self.Mat_Num[index]
#M(K or Z, M or Z)
if Var_row.__len__() == 1 :
if Var_col.__len__() == 1 :
if Var_row[0] == Var_col[0] : #M(K,M=K) or M(Z,Z)
vrk = arange(Dim_row[0]) +1
k = Symbol(str(Var_row[0]))
smat = lambdify(k, coeff, modules=libraries)(vrk)
if srepr(coeff).__contains__(srepr(Var_row[0])) :
smat = diag(smat)
print 'coeff n°', index, ' Case 1/1 M(K,M=K) or M(Z,Z) : i dependent '
print coeff, Var_col, Var_row
else :
smat = diag([smat]*Dim_row[0])
print 'coeff n°', index, ' Case 1/1 M(K,M=K) or M(Z,Z) : i non dependent'
print coeff, Var_col, Var_row
else :
if srepr(coeff).__contains__(srepr(Var_col[0]) and srepr(Var_row[0])) : #M(K,Z) or M(Z,M) or M(K, M)
print 'coeff n°', index, ' Case 1/1 M(K,Z) or M(Z,M) : i dependent '
print coeff, Var_col, Var_row, index
vrk = arange(Dim_row[0]) +1
vcm = arange(Dim_col[0]) +1
mcm, mrk = meshgrid(vcm, vrk)
k = Symbol(str(Var_row[0]))
i = Symbol(str(Var_col[0]))
smat = lambdify((k, i), coeff, modules=libraries)(mrk, mcm)
elif not(srepr(coeff).__contains__(srepr(Var_row[0]))) : #M(Z,M)
print 'coeff n°', index, ' Case 1/1 M(Z,M) : i non dependent '
print coeff, Var_col, Var_row, index
vcm = arange(Dim_col[0]) +1
m = Symbol(str(Var_col[0]))
smat = lambdify(m, coeff, modules=libraries)(vcm)
smat = [smat]*Dim_row[0]
smat = concatenate(list(smat), axis=0)
elif not(srepr(coeff).__contains__(srepr(Var_col[0]))) : #M(K,Z)
print 'coeff n°', index, ' Case 1/1 M(K,Z) : i non dependent'
print coeff, Var_col, Var_row, index
vrk = arange(Dim_row[0]) +1
k = Symbol(str(Var_row[0]))
smat = lambdify(k, coeff, modules=libraries)(vrk)
smat = [smat]*Dim_col[0]
smat = concatenate(list(smat), axis=1)
self.count = self.count +1
Mat[Pos_row:Pos_row+Nb_row, Pos_col:Pos_col+Nb_col] = smat
return Mat
In the end I fill the matrix with the lambdified coeff, which is in this case a smaller matrix of size (Nb_row, Nb_col).
I will keep searching on my own, do not hesitate to ask for more details !
--Edit 3 --
I have found that if I do this :
m = Symbol(str(Var_col[0]))
coeff = lambdify(m, coeff, modules=libraries)
for nm in range(0, Dim_col[0]) :
smat.append(coeff(nm+1))
It works but it's far more time consuming (though far less than using subs and evalf). The error appears when I call the lambda function created by lambdify with an array object (whatever it is numpy or sympy array type).
I can reproduce your error. Based on these inputs:
m = Symbol('m')
expr = -1.06048319593874*(-(3.14159265358979*m*besselj(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*besselj(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I)))*bessely(27.9937791601866*m, 6.81776274795262*sqrt(-I))/(3.14159265358979*m*bessely(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*bessely(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I))) + besselj(27.9937791601866*m, 6.81776274795262*sqrt(-I)))*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m
nm = 2
bessel = {'besselj': jv,'besselk':kv,'besseli':iv,'bessely':yv}
libraries = [bessel, "numpy"]
It works integers in vm:
vm = np.arange(nm, dtype=np.int) +1
result = lambdify(m, expr, modules=libraries)(vm)
But complex numbers produce the same error message as you got:
vm = np.arange(nm, dtype=np.complex) +1
result = lambdify(m, expr, modules=libraries)(vm)
The error message:
TypeError Traceback (most recent call last)
<ipython-input-30-f0e31009275a> in <module>()
1 vm = np.arange(nm, dtype=np.complex) +1
----> 2 result = lambdify(m, expr, modules=libraries)(vm)
/Users/mike/anaconda/envs/py34/lib/python3.4/site-packages/numpy/__init__.py in <lambda>(_Dummy_27)
TypeError: ufunc 'jv' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
So, check what data type you got in vcm, i.e. what arange(Dim_col[0]) +1 returns.
You can take only the real part of complex numbers with the attribute real. For example, vm.real gives you the real part of vm. If this is what you want, you should get your result with:
result = lambdify(m, expr, modules=libraries).(vm.real)
I'm trying to write a function encr(k,m) where the message m is any string over the characters A...Za...z and where the key k is a permutation. When len(m) isn't a multiple of len(k), then I need to append Z's to m to make len(m) a multiple of len(k).
So far I've got
import math, pyperclip
def encr(k, m):
ciphertext = [''] * k
for col in range(len(k)):
pointer = col
while pointer < len(m):
ciphertext[col] += m[pointer]
pointer += 1
return ''.join(ciphertext)
I keep getting an error: TypeError: can't multiply sequence by non-int of type 'list' on line 3, in encr ciphertext = [''] * k
Any help would be great
An example of input would be encr([3, 2, 4, 1, 0], 'SineLaboreNihil')
You current error is that k is a string in your function, and you are attempting to add that to an integer - pointer. I think you meant to add 1 to pointer.
You are also attempting to take range() on that same string. range(len(k)) is what you need to do.
Your new error can be corrected as follows -
ciphertext = [''] * len(k)
I'm defining a function in python in this way:
def calculate(y1,y2,y):
l=np.log(3)
ya=np.array(y1)/(np.array(y)*np.array(l))
yb=np.array(y2)/(np.array(y)*np.array(l))
return (ya,yb)
but when I run my script (even if everything works) I get the following error:
RuntimeWarning: invalid value encountered in divide
ya = np.array(y1)/((np.array(y))*(l))
RuntimeWarning: invalid value encountered in divide
yb = np.array(y2)/((np.array(y))*(l))
How can I solve the problem?
You're getting that error because there is either a 0 or a np.inf value in the denominator array.
There's not a lot you can do other than clean up y before it gets to calculcate
def calculate(y1, y2, y):
if not isinstance(y, np.ndarray):
y = np.array(y)
if not np.isfinite(y):
print 'bad y array values'
return
elif np.sum(y == 0) > 0:
print 'zero values in y'
return
# the rest of your code
Note this will stop the RunTimeWarning but will return nothing so the function that calls calculate will have to deal with that.