Using latest version of Python I'm using math module to calculate the trigonometric values but I'm not getting the Output I want. Program:
ans = math.sin(rad)
fracshun = ans.as_integer_ratio()
fracshun = str(fracshun[0]) "/" str(fracshun[1])
print("sin", degree, "°", " = ", fracshun, " = ", ans, sep="")
when I calculate sin of degree 45, the desired output is 1/√2, but this isn't the output I am getting, instead I get this
sin45.0° = 6369051672525773/9007199254740992 = 0.7071067811865476
And this is the case for other values like sin of 60 degree or cos of 30 degree and 45 degree How to print number as fractions that includes square roots(How to get "1/√2" from "0.7071067811865476")?
CodePudding user response:
Instead of using trigonometric functions from standard module math
, you can use trigonometric functions from sympy.
sympy is a python module designed specifically for symbolic calculations. Calculations made with sympy won't evaluate into floating-point approximations unless you explicitly ask for it.
>>> import sympy as sp
>>> sp.sin(sp.pi/2)
1
>>> sp.sin(sp.pi/4)
sqrt(2)/2
>>> sp.sin(sp.pi/4).evalf()
0.707106781186548
CodePudding user response:
First, I'd like to note that we typically dislike having radicals in the denominator; and 1 / √2 = √2 / 2, so we typically prefer the latter.
Second, to express a floating-point number x
as a multiple of √2, all you have to do is divide x
by sqrt(2)
:
from math import sqrt
x = 0.7071067811865476
r = x / sqrt(2)
print('x = {} √2'.format(r))
# x = 0.5 √2
Now, you can see that the output is still showed with a decimal point, not with a fraction. Getting a fraction back from these floating-point numbers involves quite a bit of guessing, because floating-point numbers are approximations. For instance, you can "guess" that 0.5
is 1/2, and that 0.333
is 1/3. But 0.333
is not exactly equal to 1/3. How do we choose 1/3 rather than 3/10 or 33/100 or 333/1000?
Finding the "best fraction" corresponding to an approximate number is a topic that has been extensively studied. See this wikipedia article on the topic: Best rational approximations.
In python, the algorithms described in this wikipedia article are implemented in the standard library, in method Fraction.limit_denominator
of class Fraction
in module fractions
.
Here is a function I wrote which divide a number by sqrt(2)
then uses Fraction.limit_denominator
to find a best approximating fraction and display the result nicely:
from math import sqrt
from fractions import Fraction
def float_to_sqrt2frac(x, max_denominator=180):
y = Fraction(x).limit_denominator(max_denominator)
r = Fraction(x / sqrt(2)).limit_denominator(max_denominator)
if abs(y - x) <= abs(r*sqrt(2) - x): # approximate as rational
prettyones = {1: '1', -1: '-1'}
m = ''
r = y
else: # approximate as √2 fraction
prettyones = {1: '', -1: '-'}
m = '√2'
if r == 0:
return '0'
else:
num = prettyones.get(r.numerator, str(r.numerator))
denom = '/{}'.format(r.denominator) if r.denominator != 1 else ''
return m.join((num, denom))
You can toy around with the optional parameter max_denominator
but if all your floating-point numbers were obtained as results of math.cos
, math.sin
or math.tan
operations on relatively-precise angles, it shouldn't matter too much; and if the angles are too imprecise, you can't expect this function to guess whether the result should be a multiple of √2 or not anyway.
Some tests:
import sympy
def test_sqrt2(max_denominator=40):
testcases = ['0', '1', '0.7', '0.707', '0.707107', '0.47', '1.1', '1.06', '1.0606', '1.06066', '3*sqrt(2)/4', 'sqrt(2)/8', '-sqrt(2)/4', '12*sqrt(2)/19', '-3*sqrt(2)/7', 'sin(pi/6)', 'sin(-pi/6)', 'cos(pi/6)', 'cos(45 * pi / 180)', 'sin(0.79)', 'sin(0.785)', 'sin(0.7854)']
print('max_denominator={}'.format(max_denominator))
for s in testcases:
value = float(sympy.parse_expr(s).evalf())
z = float_to_sqrt2frac(value, max_denominator=max_denominator)
print('{:13s} ----> {}'.format(s, z))
>>> test_sqrt2()
max_denominator=40
0 ----> 0
1 ----> 1
0.7 ----> 7/10
0.707 ----> √2/2
0.707107 ----> √2/2
0.47 ----> 8/17
1.1 ----> 11/10
1.06 ----> 35/33
1.0606 ----> 35/33
1.06066 ----> 3√2/4
3*sqrt(2)/4 ----> 3√2/4
sqrt(2)/8 ----> √2/8
-sqrt(2)/4 ----> -√2/4
12*sqrt(2)/19 ----> 12√2/19
-3*sqrt(2)/7 ----> -3√2/7
sin(pi/6) ----> 1/2
sin(-pi/6) ----> -1/2
cos(pi/6) ----> 13/15
cos(45 * pi / 180) ----> √2/2
sin(0.79) ----> 27/38
sin(0.785) ----> √2/2
sin(0.7854) ----> √2/2