我正在寻找一个程序,它可以为任何输入返回三角值

问题描述 投票:0回答:2

使用最新版本的Python 我正在使用数学模块来计算三角值,但我没有得到我想要的输出。 节目:

ans = math.sin(rad)
fracshun = ans.as_integer_ratio()
fracshun = str(fracshun[0])+"/"+str(fracshun[1])
print("sin", degree, "°", " = ", fracshun, " = ", ans, sep="")

当我计算 45 度的 sin 时,所需的输出是 1/√2,但这不是我得到的输出,而是得到这个

sin45.0° = 6369051672525773/9007199254740992 = 0.7071067811865476

其他值的情况也是如此,例如 60 度的 sin 或 30 度和 45 度的 cos 如何将数字打印为包含平方根的分数(如何从“0.7071067811865476”获得“1/√2”)?

python math trigonometry
2个回答
2
投票

您可以使用

sympy
中的三角函数,而不是使用标准模块 math 中的三角函数。

sympy是专门为符号计算设计的python模块。除非您明确要求,否则使用 sympy 进行的计算不会计算为浮点近似值。

>>> from sympy import pi, sin

>>> sin(pi/2)
1

>>> sin(pi/4)
sqrt(2)/2

>>> sin(pi/4).evalf()
0.707106781186548

1
投票

首先,我想指出的是,我们通常不喜欢分母中有根式;和 1 / √2 = √2 / 2,所以我们通常更喜欢后者。

其次,要将浮点数

x
表示为√2的倍数,您只需将
x
除以
sqrt(2)
即可:

from math import sqrt

x = 0.7071067811865476
r = x / sqrt(2)
print('x = {} √2'.format(r))
# x = 0.5 √2

现在,您可以看到输出仍然显示为小数点,而不是分数。从这些浮点数中获取小数涉及相当多的猜测,因为浮点数是近似值。例如,您可以“猜测”

0.5
是 1/2,
0.333
是 1/3。但
0.333
并不完全等于 1/3。我们如何选择 1/3 而不是 3/10 或 33/100 或 333/1000?

寻找与近似数字相对应的“最佳分数”是一个被广泛研究的话题。请参阅有关该主题的维基百科文章:最佳有理近似

在Python中,这篇维基百科文章中描述的算法是在标准库中,在模块

Fraction.limit_denominator
中类
Fraction
的方法
fractions
中实现的。

这是我编写的一个函数,它将数字除以

sqrt(2)
,然后使用
Fraction.limit_denominator
找到最佳近似分数并很好地显示结果:

from math import sqrt
from fractions import Fraction

def float_to_sqrt2frac(x, max_denominator=40):
    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))

您可以尝试使用可选参数

max_denominator
,但如果所有浮点数都是作为
math.cos
math.sin
math.tan
对相对精确的角度进行运算的结果而获得的,那么应该不会太重要;如果角度太不精确,无论如何你都不能指望这个函数猜测结果是否应该是 √2 的倍数。

一些测试:

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
© www.soinside.com 2019 - 2024. All rights reserved.