How to calculate the ratio between two numbers in python - python

I have to calculate the ratio between 0.000857179311146189 and 0.026955533883055983 but am unsure how to do this other than by dividing the two numbers.
Is it possible to calculate this with the result in the form 0.001714 : 0.053912

Using the fractions module:
from fractions import Fraction
num1 = Fraction(0.000857179311146189)
num2 = Fraction(0.026955533883055983)
ratio = Fraction(num1, num2).limit_denominator()
print(f"{ratio.numerator / 10**6} : {ratio.denominator / 10**6}")
# 0.027671 : 0.870164

I understand OP issue, but the 2 pair-numbers you provided is not the same ratio
Your problem is to find the greatest common divisor, for float
https://stackoverflow.com/a/45325587/3789481
def float_gcd(a, b, rtol = 1e-05, atol = 1e-08):
t = min(abs(a), abs(b))
while abs(b) > rtol * t + atol:
a, b = b, a % b
return a
x = 0.000857179311146189
y = 0.026955533883055983
div = float_gcd(x, y)
print(f"{x/div}:{y/div}")
#Result: 34462.78514615594:1083743.8102297517
I believe 34462.78514615594:1083743.8102297517 is the nearest ratio you would like to get, let's check
For int, we could use math library
https://stackoverflow.com/a/65640573/3789481
import math
div = math.gcd(x, y)
print(f"{x/div}:{y/div}")

Related

How will I convert decimals into accurate fractions or accurate decimals?

For some reason it shows an error message: TypeError: argument should be a string or a Rational instance
import cmath
from fractions import Fraction
#Function
# Quadratic equatrion solver
def solver(a_entry, b_entry, c_entry):
a = int(a_entry)
b = int(b_entry)
c = int(c_entry)
d = (b*b) - (4*a*c)
sol1 = (-b-cmath.sqrt(d)/(2*a))
sol2 = (-b+cmath.sqrt(d)/(2*a))
sol3 = Fraction(sol1)
sol4 = Fraction(sol2)
print(f"Value of x1 = {sol3} and value of x2 = {sol4}")
solver(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in solver
File "/usr/lib/python3.10/fractions.py", line 139, in __new__
raise TypeError("argument should be a string "
TypeError: argument should be a string or a Rational instance
I am a new programmer and I saw that this code generates a weird number (example: 5.42043240824+0j {inaccurate values})
when i give random values. So I want it to give either an accurate decimal values or in fraction. The fraction method dosen't work for some reason. Can someone please help. Alot of thanks.
2 things wrong in your code :
Use math instead of cmath as cmath is used for complexed values (it will always returns a complexe value, even 1+0j) which is not compatible with Fraction.
Be careful you wrote : (-b-cmath.sqrt(d)/(2*a)) but is should be ((-b-cmath.sqrt(d))/(2*a))
Also, the solution might no exist. For example, resolving 1x^2 + 3x + 10 has no answer (your fonction does not cross x axe). It still has complexe answer(s).
To avoid this you can use a try except to catch errors. OR you can validate that d^2 is greater than 4ac because you can't sqrt negative values (except with complexe values ;) ) :
def solver():
a = int(entry.get())
b = int(entry1.get())
c = int(entry2.get())
d = (b*b) - (4*a*c)
if d < 0:
text = "no real answer ! The function doesn't cross X axe !"
label2.configure(text = text)
else:
sol1 = ((-b-math.sqrt(d))/(2*a))
sol2 = ((-b+math.sqrt(d))/(2*a))
sol3 = Fraction(sol1)
sol4 = Fraction(sol2)
label2.configure(text = f"Value of x1 = {sol3} and value of x2 = {sol4}")
Hope it helps
The issue with sqrt
It appears that you do not want to evaluate the square roots to numerical approximations. But that is exactly what cmath.sqrt and math.sqrt do: they calculate numerical approximations of square roots.
For instance:
import math
print( math.sqrt(2) )
# 1.4142135623730951
If you are not interested in numerical approximations, then I suggest using a library for symbolic calculus. The best-known library for symbolic calculus in python is called sympy. This module has a sympy.sqrt function that will simplify a square root as much as it can, but without returning a numerical approximation:
import sympy
print( sympy.sqrt(9) )
# 3
print( sympy.sqrt(2) )
# sqrt(2)
print( sympy.sqrt(18) )
# 3*sqrt(2)
More information about sympy: https://docs.sympy.org/latest/tutorials/intro-tutorial/intro.html
Other advice
When you write a program, it is most usually a good idea to cleanly separate the parts of the code that deal with algorithms, maths, and logic, from the parts of the code that deal with input and output. I suggest writing two functions, one that solves quadratic equations, and one that does input and output:
import sympy
# returns solutions of a x**2 + b x + c == 0
def solver(a, b, c):
Delta = b*b - 4*a*c
sol1 = (-b - sympy.sqrt(Delta)) / (2*a)
sol2 = (-b + sympy.sqrt(Delta)) / (2*a)
return (sol1, sol2)
# ask for user input and solve an equation
def input_equation_output_solution():
a = int(entry.get())
b = int(entry1.get())
c = int(entry2.get())
sol1, sol2 = solver(a, b, c)
label2.configure(text = f"Value of x1 = {sol1} and value of x2 = {sol2}")

Why is my RSA key function returning nan?

I am currently working on a project replicating RSA key generation and testing using euclidean algorithm, extended euclidean algorithm to find the modular inverse of the value.
I used the Miller-Rabin test to choose two prime numbers, p and q.
After running the code, I am able to obtain Kpub and e, however Kpr returns as nan.
Please help!
#Euclidean Algorithm func
def EucAlgo(a, b):
if a==0:
return b
return EucAlgo(b % a,a)
def ExEucAlgo(a,b):
if a==0:
return b,0,1
gcd, s1, t1 = ExEucAlgo(b%a,a)
#gcd of a,b
s = t1 - (b/a) * s1
t = s1
return gcd, s, t
def ExEucAlgo_modInverse(a,b):
gcd, s, t = ExEucAlgo(b,a)
if (gcd == 1):
i = t % a
elif (gcd !=1):
print("There is no inverse modulo for the input.")
return i
def SqMul_ModularExpo(b, exp, n):
bin_exp = bin(exp)
base = b
for i in range (3, len(bin_exp)):
base = (base ** 2) % n
if(bin_exp[i]=='1'):
i+=1
base = (base * b) %n
return base
#RSA Key generation
p=9054583561027584891319616491815785011595937977633787663340258672121877196627062461308487615739189212918799813327175451021729047602129396754172486202100997
q=10115395220079214686776355235686624745626962891667413288473649946208213820942557513105240135405981494333016032659525466362014175268953946332375459648688023
n= p * q
phi_n= (p-1) * (q-1)
e= randint(1, phi_n - 1)
while((EucAlgo(e,phi_n)) !=1):
e = randint(1, (phi_n-1))
d = ExEucAlgo_modInverse(e,phi_n)
print(f"\nKpr={d}")
print(f"\nKpub=(n={n})\n \ne={e}")
The problem is that you are using float point division which will result in returning float a point which when dealing with large int can result in very large floats which python can't handle so the solution is to use integer division which means 5//2=2 not 2.5. The problem is that Now encrypting and decrypting data would result in wrong decryption. (You wont get 2 again) because of some bugs in your functions.
FIRST: use public exponent pf 65537(prime number) which is the default for all RSA implementations(see your browser certificates) rather than finding a random one. Then after calculating the extended Euclidean algorithm which is used to find modulo inverse you dont have to make any more calculations(just return this value if GCD is 1 otherwise raise an error or whatever).
Here is the complete code that works after removing some unneeded (functions, imports, and random public exponent) READ comments.
def EucAlgo(a, b):
if a == 0:
return b
return EucAlgo(b % a, a)
def ExEucAlgo(a,b):
if a==0:
return b, 0, 1
gcd, s1, t1 = ExEucAlgo(b%a, a)
# You dont use / use // to make integer division
s = t1 - (b//a) * s1
t = s1
return gcd, s, t
def ExEucAlgo_modInverse(a,b):
gcd, s, t = ExEucAlgo(a, b)
if (gcd == 1):
# Just return s which is the inverse of public exponent
return s
elif (gcd != 1):
# I think it's better to raise an error but it's up to you
print("There is no inverse modulo for the input.")
#RSA Key generation
p = 9054583561027584891319616491815785011595937977633787663340258672121877196627062461308487615739189212918799813327175451021729047602129396754172486202100997
q = 10115395220079214686776355235686624745626962891667413288473649946208213820942557513105240135405981494333016032659525466362014175268953946332375459648688023
n = p * q
phi_n = (p-1) * (q-1)
# Just use fixed prime public exponent rather than trying fixed ones
e = 65537
d = ExEucAlgo_modInverse(e, phi_n)
print(f"\nKpr={d}")
print(f"\nKpub=(n={n})\n \ne={e}")
# Try to encrypt and decrypt 36
ciphertext = pow(36, e, n)
print("Encrypted data {}".format(ciphertext))
print("Decrypted data is {}".format(pow(ciphertext, d, n)))

working with large numbers in the fraction module in Python

EDIT: solved but since the solution was in the comments and I cant accept my own solution reffering to the comment till tomorrow it is still open. Once again a big thank you to this great community and its people
optional context: I am computing sollutions for the Pell equation
http://mathworld.wolfram.com/PellEquation.html
On the buttom of the page is a table with values for D -> x, y.
My code works perfectly for EVERY VALUE EXCEPT D = 61. I believe it could have something to do with the values of x and y being very big and maybe the fraction module cant handle such big numbers and there is an overflow?
I made the observation, that whether I give my input/ starting value as a fraction or a decimal changes my solution (but only for D = 61).
Why is my code failing with the value of D = 61? What do I need to change/use to get it to work? Thank you very much for your time and help.
code:
from math import sqrt, floor
from fractions import Fraction
def continued_fraction(D):
# to make sure it is not a problem on converting decimals to fractions I made EVERYTHING a fraction (which shouldnt and didnt affect the output)
# input is the value for D, output is a tuple with (x, y)
D = Fraction(sqrt(D))
aS = []
a0 = D
r1 = Fraction(D - floor(D))
a = Fraction(a0 - r1)
r = Fraction(-1)
count = 0
while a <= 2*floor(D):
aS.append((a, count))
if a == 2*floor(D):
if count % 2 == 0:
break
else:
r = count
if count == 2*r:
break
try:
a0 = Fraction(1/r1)
except ZeroDivisionError:
break
r1 = Fraction(a0 - floor(a0))
a = Fraction(a0 - r1)
count += 1
pS = []
qS = []
a0 = Fraction(floor(D))
p0 = a0
p1 = Fraction(a0 * aS[1][0] + 1)
q0 = Fraction(1)
q1 = Fraction(aS[1][0])
count = 2
while count < len(aS):
pS.append((p0, count - 2))
qS.append((q0, count - 2))
pn = Fraction(aS[count][0] * p1 + p0)
qn = Fraction(aS[count][0] * q1 + q0)
p0 = Fraction(p1)
p1 = Fraction(pn)
q0 = Fraction(q1)
q1 = Fraction(qn)
count += 1
pS.append((p0, count-1))
#pS.append((p1, count))
qS.append((q0, count - 1))
#qS.append((q1, count))
#print(pS)
#print(qS)
return Fraction(pS[-1][0]), Fraction(qS[-1][0])
print(continued_fraction(Fraction(61)))
Fraction(1/r1) means to compute the reciprocal of r1 as an inexact floating-point number, and then find a rational approximation of that inexact number. You want Fraction(1, r1) to directly specify the numerator and denominator of your fraction, without any approximation errors creeping in.
A big thanks to GalAbra and jasonharper for your responds. After knowing with certainty, that it is a percision problem (thank you GalAbra) I knew I needed more decimals for the sqrt(D). I used the decimal module from Python:
from decimal import *
getcontext().prec = 1000
D = Fraction(Decimal(D).sqrt())
with this and the change suggested by jasonharper (thank you again) it works now.

rounding in python not working

I've been having trouble trying to round my answer for a problem where I find the area of a regular polygon and then square the perimeter. My final answer should be the area plus the perimeter(squared), rounded to 4 decimal places. My math seems to be correct, however, no matter what numbers I use for inputs, there are only zeros after the decimal. I have included a screen shot of my code and incorrect message from the checker that I use.
import math
def polysum(n, s):
a = ((0.25 * n * s ** 2) / (math.tan(math.pi / 2)))
p = ((n * s) ** 2)
total = a + p
return '%.4f' % round(total)
print polysum(8, 8)
Of course you're only getting zeroes after the decimal point, because you are using the round() function to chop off all digits after the decimal point. If that's not what you want, don't do it. Just do:
return "%.4f" % total
Or possibly:
return round(total, 4)
There are two issues:
Change return '%.4f' % round(total) to return round(total,4) or else you are returning a str round to the nearest integer. It looks like the expected output is a float.
The factor of math.tan(math.pi / 2) is incorrect. This should evaluate to infinity (if not for floating point approximations) and is clearly not what you want. It should be math.tan(math.pi / 2 / n).
import math
def polysum(n, s):
a = (0.25 * n * s ** 2) / (math.tan(math.pi / n))
p = ((n * s) ** 2)
total = a + p
ans = round(total, 4)
return ans
print polysum(8,8)
print polysum(4, 89)
from math import *
def polysum(n, s):
lst = [(0.25 * n * s **2) / tan(pi / n), ((n * s) ** 2)]
return round(sum(lst), 4)
I have tried both the test cases. The output is matching.

Fastest possible method for the arcsin function on small, arbitrary floating-point values

I need to calculate the arcsine function of small values that are under the form of mpmath's "mpf" floating-point bignums.
What I call a "small" value is for example e/4/(10**7) = 0.000000067957045711476130884...
Here is a result of a test on my machine with mpmath's built-in asin function:
import gmpy2
from mpmath import *
from time import time
mp.dps = 10**6
val=e/4/(10**7)
print "ready"
start=time()
temp=asin(val)
print "mpmath asin: "+str(time()-start)+" seconds"
>>> 155.108999968 seconds
This is a particular case: I work with somewhat small numbers, so I'm asking myself if there is a way to calculate it in python that actually beats mpmath for this particular case (= for small values).
Taylor series are actually a good choice here because they converge very fast for small arguments. But I still need to accelerate the calculations further somehow.
Actually there are some problems:
1) Binary splitting is ineffective here because it shines only when you can write the argument as a small fraction. A full-precision float is given here.
2) arcsin is a non-alternating series, thus Van Wijngaarden or sumalt transformations are ineffective too (unless there is a way I'm not aware of to generalize them to non-alternating series).
https://en.wikipedia.org/wiki/Van_Wijngaarden_transformation
The only acceleration left I can think of is Chebyshev polynomials. Can Chebyshev polynomials be applied on the arcsin function? How to?
Can you use the mpfr type that is included in gmpy2?
>>> import gmpy2
>>> gmpy2.get_context().precision = 3100000
>>> val = gmpy2.exp(1)/4/10**7
>>> from time import time
>>> start=time();r=gmpy2.asin(val);print time()-start
3.36188197136
In addition to supporting the GMP library, gmpy2 also supports the MPFR and MPC multiple-precision libraries.
Disclaimer: I maintain gmpy2.
Actually binary splitting does work very well, if combined with iterated argument reduction to balance the number of terms against the size of the numerators and denominators (this is known as the bit-burst algorithm).
Here is a binary splitting implementation for mpmath based on repeated application of the formula atan(t) = atan(p/2^q) + atan((t*2^q-p) / (2^q+p*t)). This formula was suggested recently by Richard Brent (in fact mpmath's atan already uses a single invocation of this formula at low precision, in order to look up atan(p/2^q) from a cache). If I remember correctly, MPFR also uses the bit-burst algorithm to evaluate atan, but it uses a slightly different formula, which possibly is more efficient (instead of evaluating several different arctangent values, it does analytic continuation using the arctangent differential equation).
from mpmath.libmp import MPZ, bitcount
from mpmath import mp
def bsplit(p, q, a, b):
if b - a == 1:
if a == 0:
P = p
Q = q
else:
P = p * p
Q = q * 2
B = MPZ(1 + 2 * a)
if a % 2 == 1:
B = -B
T = P
return P, Q, B, T
else:
m = a + (b - a) // 2
P1, Q1, B1, T1 = bsplit(p, q, a, m)
P2, Q2, B2, T2 = bsplit(p, q, m, b)
T = ((T1 * B2) << Q2) + T2 * B1 * P1
P = P1 * P2
B = B1 * B2
Q = Q1 + Q2
return P, Q, B, T
def atan_bsplit(p, q, prec):
"""computes atan(p/2^q) as a fixed-point number"""
if p == 0:
return MPZ(0)
# FIXME
nterms = (-prec / (bitcount(p) - q) - 1) * 0.5
nterms = int(nterms) + 1
if nterms < 1:
return MPZ(0)
P, Q, B, T = bsplit(p, q, 0, nterms)
if prec >= Q:
return (T << (prec - Q)) // B
else:
return T // (B << (Q - prec))
def atan_fixed(x, prec):
t = MPZ(x)
s = MPZ(0)
q = 1
while t:
q = min(q, prec)
p = t >> (prec - q)
if p:
s += atan_bsplit(p, q, prec)
u = (t << q) - (p << prec)
v = (MPZ(1) << (q + prec)) + p * t
t = (u << prec) // v
q *= 2
return s
def atan1(x):
prec = mp.prec
man = x.to_fixed(prec)
return mp.mpf((atan_fixed(man, prec), -prec))
def asin1(x):
x = mpf(x)
return atan1(x/sqrt(1-x**2))
With this code, I get:
>>> from mpmath import *
>>> mp.dps = 1000000
>>> val=e/4/(10**7)
>>> from time import time
>>> start = time(); y1 = asin(x); print time() - start
58.8485069275
>>> start = time(); y2 = asin1(x); print time() - start
8.26498985291
>>> nprint(y2 - y1)
-2.31674e-1000000
Warning: atan1 assumes 0 <= x < 1/2, and the determination of the number of terms might not be optimal or correct (fixing these issues is left as an exercise to the reader).
A fast way is to use a pre-calculated look-up table.
But if you look at e.g. a Taylor series for asin;
def asin(x):
rv = (x + 1/3.0*x**3 + 7/30.0*x**5 + 64/315.0*x**7 + 4477/22680.0*x**9 +
28447/138600.0*x**11 + 23029/102960.0*x**13 +
17905882/70945875.0*x**15 + 1158176431/3958416000.0*x**17 +
9149187845813/26398676304000.0*x**19)
return rv
You'll see that for small values of x, asin(x) ≈ x.
In [19]: asin(1e-7)
Out[19]: 1.0000000000000033e-07
In [20]: asin(1e-9)
Out[20]: 1e-09
In [21]: asin(1e-11)
Out[21]: 1e-11
In [22]: asin(1e-12)
Out[22]: 1e-12
E.g. for the value us used:
In [23]: asin(0.000000067957045711476130884)
Out[23]: 6.795704571147624e-08
In [24]: asin(0.000000067957045711476130884)/0.000000067957045711476130884
Out[24]: 1.0000000000000016
Of course it depends on whether this difference is relevant to you.

Categories

Resources