Need help regarding Binary Powering with a matrix - python

I am trying to write a program that can calculate the nth power of 2x2 matrix using binary powering. I would really appreciate the help. My problem is that the code is only working for a matrix to the power of 2.
def binPow(m,n):
if (n==0): return[[1,0],[0,1]]
q = binPow(m,n//2)
square = MatrMult(o,o)
if (n%2==0):
return square
else:
return MatrMult(m,square)
def MatrMult(o,x):
o = [[b,c],[e,f]]
g = [[(b*b)+(c*e),(b*c)+(c*f)],[(e*b)+(f*e),(e*c)+(f*f)]]
return(g)
b = int(input("Enter A1: "))
c = int(input("Enter A2: "))
e = int(input("Enter A3: "))
f = int(input("Enter A4: "))
o = [[b,c],[e,f]]
n = int(input("Enter Power: "))
print(o, "to the power of", n, " is ", binPow(o,n))

In Python3, n/2 will result in a floating point number. 1/2 is 0.5, 0.5/2 is 0.25, 0.25/2 is 0.125, etc. It never gets to 0, so if (n==0): ... will never execute. To make sure that n is always a whole number, double your slashes: q = binPow(m, n//2). That way, 5//2 becomes 2 instead of 2.5, etc. Your real problem is how you are multiplying the matrices. You are always squaring the original matrix because you don't do anything with the parameters given you. I also took the liberty of modifying your binPow() function to something a little simpler:
def binPow(m,n):
if (n==0): return[[1,0],[0,1]]
q = m
while n > 1:
q = MatrMult(m, q)
n -= 1
return q
def MatrMult(o,x):
((a, b), (c, d)) = o
((e, f), (g, h)) = x
g = [[(a*e)+(b*g),(a*f)+(b*h)],[(c*e)+(d*g),(c*f)+(d*h)]]
return(g)

Related

Errors in Directly vs Recursively Calculating a given Fibonacci Number

I was bored at work and was playing with some math and python coding, when I noticed the following:
Recursively (or if using a for loop) you simply add integers together to get a given Fibonacci number. However there is also a direct equation for calculating Fibonacci numbers, and for large n this equation will give answers that are, frankly, quite wrong with respect to the recursively calculated Fibonacci number.
I imagine this is due to rounding and floating point arithmetic ( sqrt(5) is irrational after all), and if so can anyone point me into a direction on how I could modify the fibo_calc_direct function to return a more accurate result?
Thanks!
def fib_calc_recur(n, ii = 0, jj = 1):
#n is the index of the nth fibonacci number, F_n, where F_0 = 0, F_1 = 1, ...
if n == 0: #use recursion
return ii
if n == 1:
return jj
else:
return(fib_calc_recur(n -1, jj, ii + jj))
def fib_calc_direct(n):
a = (1 + np.sqrt(5))/2
b = (1 - np.sqrt(5))/2
f = (1/np.sqrt(5)) * (a**n - b**n)
return(f)
You could make use of Decimal numbers, and set its precision depending on the magninute of n
Not your question, but I'd use an iterative version of the addition method. Here is a script that makes both calculations (naive addition, direct with Decimal) for values of n up to 4000:
def fib_calc_iter(n):
a, b = 0, 1
if n < 2:
return n
for _ in range(1, n):
a, b = b, a + b
return b
from decimal import Decimal, getcontext
def fib_calc_decimal(n):
getcontext().prec = n // 4 + 3 # Choose a precision good enough for this n
sqrt5 = Decimal(5).sqrt()
da = (1 + sqrt5) / 2
db = (1 - sqrt5) / 2
f = (da**n - db**n) / sqrt5
return int(f + Decimal(0.5)) # Round to nearest int
# Test it...
for n in range(1, 4000):
x = fib_calc_iter(n)
y = fib_calc_decimal(n)
if x != y:
print(f"Difference found for n={n}.\nNaive method={x}.\nDecimal method={y}")
break
else:
print("No differences found")

Equation solving using bisection method using python

I wrote a python code to find root of 2*x-4 using bisection method
def func(x):
return 2*x-4
def bisection(a,b):
if (func(a) * func(b) >= 0):
print("You have not assumed right a and b\n")
return
c = a
while ((b-a) >= 0.01):
c = (a+b)/2
if (func(c) == 0.0):
break
if (func(c)*func(a) < 0):
b = c
else:
a = c
print("The value of root is : ","%.0f"%c)
a =-2
b = 4
bisection(a, b)
Now i want that the function input should be given by the user in the form of mx+n where m and n are integers. Can anyone help how can i do that ?
m, n = list(map(int, input("Please enter the value of [m] [n] for f(x) = mx +n: ").split()))
def Input():
a, b = list(map(int, input("Enter values of [a] [b]: ").split()))
if f(a)*f(b)<0:
Bisection(a, b)
else:
print("Oops! The root of function doesn't belong to the above domain\nPlease try to again:")
Input()
def f(x):
return m*x + n
def Bisection(a, b):
c = (a+b)/2
if f(c)*f(b)<0:
Bisection(c, b)
elif f(c)*f(a)<0:
Bisection(c, a)
elif f(c)==0:
print(c)
Input()
See we know that Bisection, Newton-Raphson, or most of all Numerical methods are the iteration processes so better we use function inside of function: f(f(f(f.....) Of course! by checking the conditions.
Here, I have used elif f(c)==0 this is something which we can't use for quadratic/cubic or higher-order polynomials because getting the exact root will not be possible for all the types of equations say like f(x) = mx^2 - n where m, n > 0 However, we can define the iterations to be performed.
By asking like Please enter the number of iterations to be performed:

Function to solve fractions does not work with negative numbers or zeros

def fraction(a=None, b=None):
if a is None:
a = int(input("Enter the value of a "))
if b is None:
b = int(input("Enter the value of b "))
for i in range(1, min(a, b) + 1):
if a % i == 0 and b % i == 0:
gcf = i
print(a//gcf, "/", b//gcf)
fraction()
I would like for this to add a negative number to the front of the fraction when 1 input is negative and have no change when both are negative. For 0's, if the denominator is 0 produce an output of "invalid" and if the numerator is 0 have an output of 0.
However, my i in range is stopping this from happening. How could I try solving this issue?
First make sure that b is not negative. If it is, flip both signs. And then use abs(a) in the range.
Your code should also initialise gcf to 1, as there is a possibility the loop will not make iterations (i.e. when a is 0). And as then gcf is already 1, you might as well start the loop at 2.
Also, don't do I/O in such a function; always separate I/O from algorithmic logic. Perform I/O tasks outside of the function.
Here is how it could work:
def fraction(a, b):
if b < 0:
a = -a
b = -b
gcf = 1
for i in range(2, min(abs(a), b) + 1):
if a % i == 0 and b % i == 0:
gcf = i
return a//gcf, b//gcf
a = int(input("Enter the value of a "))
b = int(input("Enter the value of b "))
a, b = fraction(a, b)
print(a, "/", b)
Note that there are more efficient algorithms for getting the greatest common divisor.

(RSA) This script I got off of stackoverflow returns a negative d value

So I stumbled upon this thread on here with this script and it returns a negative d value and my p and q values are both prime. Any reason for this? Possibly just a faulty script?
def egcd(a, b):
x,y, u,v = 0,1, 1,0
while a != 0:
q, r = b//a, b%a
m, n = x-u*q, y-v*q
b,a, x,y, u,v = a,r, u,v, m,n
gcd = b
return gcd, x, y
def main():
p = 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
q = 156408916769576372285319235535320446340733908943564048157238512311891352879208957302116527435165097143521156600690562005797819820759620198602417583539668686152735534648541252847927334505648478214810780526425005943955838623325525300844493280040860604499838598837599791480284496210333200247148213274376422459183
e = 65537
ct = 313988037963374298820978547334691775209030794488153797919908078268748481143989264914905339615142922814128844328634563572589348152033399603422391976806881268233227257794938078078328711322137471700521343697410517378556947578179313088971194144321604618116160929667545497531855177496472117286033893354292910116962836092382600437895778451279347150269487601855438439995904578842465409043702035314087803621608887259671021452664437398875243519136039772309162874333619819693154364159330510837267059503793075233800618970190874388025990206963764588045741047395830966876247164745591863323438401959588889139372816750244127256609
# compute n
n = p * q
# Compute phi(n)
phi = (p - 1) * (q - 1)
# Compute modular inverse of e
gcd, a, b = egcd(e, phi)
d = a
print( "n: " + str(d) );
# Decrypt ciphertext
pt = pow(ct,d,n)
print( "pt: " + str(pt) )
if __name__ == "__main__":
main()
This can happen, I'll explain why below, but for practical purposes you'll want to know how to fix it. The answer to that is to add phi to d and use that value instead: everything will work as RSA should.
So why does it happen? The algorithm computes the extended gcd. The result of egcd is a*e + b*phi = gcd, and in the case of RSA, we have gcd = 1 so a*e + b*phi = 1.
If you look at this equation modulo phi (which is the order of the multiplicative group), then a*e == 1 mod phi which is what you need to make RSA work. In fact, by the same congruence, you can add or subtract any multiple of phi to a and the congruence still holds.
Now look at the equation again: a*e + b*phi = 1. We know e and phi are positive integers. You can't have all positive integers in this equation or else no way would it add up to 1 (it would be much larger than 1). So that means either a or b is going to be negative. Sometimes it will be a that is negative, other times it will be b. When it is b, then your a comes out as you would expect: a positive integer that you then assign to the value d. But the other times, you get a negative value for a. We don't want that, so simply add phi to it and make that your value of d.

How to make python print 1 as opposed to 1.0

I am making a math solving program, it keeps printing the whole numbers as decimals. Like 1 is 1.0, 5 is 5.0, and my code is:
print("Type in the cooridinates of the two points.")
print("")
print("---------------------")
print("First point:")
x1 = int(input("X: "))
y1 = int(input("Y: "))
print("")
print("---------------------")
print("Second point:")
x2 = int(input("X: "))
y2 = int(input("Y: "))
m = (y1-y2) / (x1-x2)
b = y1 - m * x1
round(m, 0)
round(b, 0)
print("Completed equation:")
print("")
if b < 0:
print("Y = "+ str(m) +"X - "+ str(b) +".")
elif b > 0:
print("Y = "+ str(m) +"X + "+ str(b) +".")
elif b == 0:
print("Y = "+ str(m) +"X.")
input("Press enter to continue.")
Since you're dividing integers, Python represents the result as a float, not as an int. To format the floats as you'd like, you'll have to use string formatting:
>>> print('{:g}'.format(3.14))
3.14
>>> print('{:g}'.format(3.0))
3
So plugging it into your code:
print("Y = {:g}X - {}.".format(m, b))
Try this,
> x = 10.0
> print int(x)
10
> print x
> 10.0
Is this what you are really looking for?
When you do this:
m = (y1-y2) / (x1-x2)
You get a float (a floating point representation of a real number), not an int (an integer).
Then, because m is a float, b too is a float. Then, when you call str on a float, you get a decimal point.
The right way to fix this depends on what you actually want to do.
If you really want to deal only with integers, you can use integer division:
m = (y1-y2) // (x1-x2)
That means if, say, x1, x2, y1, y2 = 4, 2, 2, 1 you'll end up with b = 2 (2 - 0 * 4). I suspect that isn't what you want; you actually want to multiply that 4 by 1/2, and then round the result afterward.
In that case, you can do the conversion the same place you round:
m = int(round(m, 0))
b = int(round(b, 0))
Note that your existing calls to round didn't actually do anything; round(m, 0) doesn't modify m, it returns a new value that's the rounded version of m, which you have to assign back to m (or somewhere else).
One more thing to consider: You probably really do want literally one half, not "the closest floating point representation to 0.5".
You probably don't actually care about the difference—unless you're using quite large integers, the rounding errors won't ever be visible. But if you do care, you may want to consider using a third-party exact-fraction module (e.g., clnum), or possibly the standard library decimal. This would mean you have to be more explicit, so I wouldn't do this unless you expect it to be necessary. But if it is necessary, it would look something like this:
m = decimal.Decimal(y1-y2) / (x1-x2)
b = y1 - m * x1
m = int(m.to_integral(rounding=decimal.ROUND_HALF_UP))
b = int(b.to_integral(rounding=decimal.ROUND_HALF_UP))
Finally, you can always keep the numbers around as floats (or Decimals, etc.), never rounding or converting them, and force them to print as integers anyway:
print("Y = {:.0g}X - {:.0g}.".format(m, b))
Just tried this one
n = -0.0
#n = 0.0
#n = +0.0
#n = 5.0
#n = 5
#n = 5.4
#n = -5.0
#n = -5
#n = 5.25
n = (n**2)**0.5
n = '{:g}'.format(n)
if n.find('.') == -1:
n=int(n)
else:
n=float(n)
print(n)
print(type(n))
-------------------------------------------------------------------
The same in one line
n = -0.0
n = int('{:g}'.format((n**2)**0.5)) if
'{:g}'.format((n**2)**0.5).find('.') == -1 else
float('{:g}'.format((n**2)**0.5))
-------------------------------------------------------------------
Example for a list
numlist = [-0.0, 0.0, +0.0, 5.0, 5, 5.4, +5.0, +5, +5.15,-5.0, -5, 5.25]
print(f'Numbers are {numlist}')
for n in numlist:
print(f'Before n is {n} and type of n is {type(n)}')
n = int('{:g}'.format((n**2)**0.5)) if '{:g}'.format((n**2)**0.5).find('.')
== -1 else float('{:g}'.format((n**2)**0.5))
print(f'After n is {n} and type of n is {type(n)}')

Categories