【问题标题】:Issue with program to approximate sin and cosine values近似正弦和余弦值的程序问题
【发布时间】:2014-03-31 22:40:58
【问题描述】:

我正在尝试编写一个程序,它以度为单位,并根据用户选择的多个给定项来近似 sin 和 cos 值。如果你不知道 how寻找罪和cos。所以,话虽如此,这是我当前的代码:

import math
def main():
    print()
    print("Program to approximate sin and cos.")
    print("You will be asked to enter an angle and \na number of terms.")
    print("Written by ME")
    print()

    sinx = 0
    cosx = 0

    x = int(input("Enter an angle (in degrees): "))
    terms = int(input("Enter the number of terms to use: "))
    print()

    for i in range(1, terms+1):
        sinx = sinx + getSin(i, x)
        cosx = cosx + getCos(i, x)

    print(cosx, sinx)

def getSin(i, x):
    if i == 1:
        return x
    else:
        num, denom = calcSinFact(i, x)
        sin = num/denom
        return sin

def getCos(i, x):
    if i == 1:
        return 1
    else:
        num, denom = calcCosFact(i, x)
        cos = num/denom
        return cos

def calcSinFact(i, x):
    if i % 2 == 1:
        sign = -1
    if i % 2 == 0:
        sign = +1
    denom = math.factorial(i*2-1)
    num = sign * (x**(i*2-1))
    return num, denom

def calcCosFact(i, x):
    if i % 2 == 1:
        sign = -1
    if i % 2 == 0:
        sign = +1
    denom = math.factorial(i*2)
    num = sign * (x**(i*2))
    return num, denom

它可以运行,但如果我使用上图所示的示例,我会得到 cos = -162527117141.85715 和 sin = -881660636823.117。很明显有些事情不对劲。在上图中,答案应该是 cos = 0.50000000433433 和 sin = 0.866025445100。我假设这是我在第一个循环中将值相加的方式,但我可能是错的。任何帮助表示赞赏!

【问题讨论】:

  • 如果关闭,您期望的值是多少?
  • 大胆猜测:您以度为单位输入,并在需要弧度的算法中使用它。尝试将初始输入乘以 pi/180。
  • 而且你的条款是错误的。尝试在getSin()getCos() 中添加打印语句以打印术语索引、分子和分母,以找出哪里出错了。

标签: python math


【解决方案1】:

这里有几个问题,正如Russell Borogove's comments 中指出的那样。

问题 1 是您使用的公式

(请参阅wikipedia)期望 x弧度 为单位,而不是度数。绕一圈是 360 度或 2*pi,所以你可以通过乘以 pi/180 将度数转换为弧度,如下 python 代码所示,错误地然后正确地得到 90 度的 sin。

>>> math.sin(90)
0.8939966636005579
>>> math.sin(90*math.pi/180)
1.0

问题 2 是代码的其余部分。正如 cmets 中所指出的,存在一些错误,找到它们的最佳方法是使用一些战略性的 print 语句。但是,您可以用更少的代码行编写程序,而且更简单的程序往往有更少的错误,并且如果它们确实有问题,也更容易调试。

由于这是一个作业,我不会为你做,但一个相关的例子是 sinh(x) 的系列。

(再次来自维基百科)

您可以使用 Python list comprehension 在“一次”中生成术语。该列表可以通过printed 和summed 来获取结果,如下程序所示

x = 90 * math.pi / 180 # 90 degrees
n = 5
terms = [x**(2*i+1)/math.factorial(2*i+1) for i in range(n)]
print terms
sinh = sum(terms)
print sinh, math.sinh(x)

这个程序的输出是

[1.5707963267948966, 0.6459640975062462, 0.07969262624616703, 0.004681754135318687, 0.00016044118478735975]
2.30129524587 2.30129890231

我直接根据求和的数学公式生成了 Python 列表理解代码,该求和公式在左侧以“Sigma”表示法方便地给出。你可以用类似的方式产生 sin 和 cos。您需要的一个缺失成分是系列中每个点的标志。数学公式告诉您需要 (-1)n。 Python 等价物是(-1)**n,可以将其插入列表理解代码中的适当位置。

【讨论】:

    【解决方案2】:

    首先,几点说明。最好将\n 打印在上一次打印的末尾或以下打印的开头,然后清空print()。 使用调试工具、使用logging 模块或仅使用print 并通过将预期值与返回值进行比较来查找错误非常有用。

    这是对我有用的代码:

    import math
    
    def main():
        print()
        print("Program to approximate sin and cos.")
        print("You will be asked to enter an angle and \na number of terms.")
        print("Written by ME")
        print()
    
        sinx = 0
        cosx = 0
    
        x = int(input("Enter an angle (in degrees): "))
        terms = int(input("Enter the number of terms to use: "))
        print()
    
        x = x / 180.0 * math.pi; # added
    
        for i in range(1, terms+1):
            sinx = sinx + getSin(i, x)
            cosx = cosx + getCos(i, x)
    
        print("Cos:{0}, Sinus:{1}".format(cosx,sinx)); # changed
    
    def getSin(i, x):
        if i == 1:
            return x
        else:
            num, denom = calcSinFact(i, x)
            sin = float(num)/denom # changed
            return sin
    
    def getCos(i, x):
        if i == 1:
            return 1
        else:
            num, denom = calcCosFact(i, x)
            cos = float(num)/denom # changed
            return cos
    
    def calcSinFact(i, x):
        if i % 2 == 1:
            sign = +1 # changed
        if i % 2 == 0:
            sign = -1 # changed
        denom = math.factorial(i*2-1)
        num = sign * (x**(i*2-1))
        return num, denom
    
    def calcCosFact(i, x):
        if i % 2 == 1:
            sign = +1 # changed
        if i % 2 == 0:
            sign = -1 # changed
        denom = math.factorial(i*2-2) # changed
        num = sign * (x**(i*2-2)) # changed
        return num, denom
    

    我改变了什么? (我希望我不会忘记任何事情)

    1. 您的sign 变量错误。恰好相反。所以我改变了条件中的标志。
    2. 也许没有必要,但当您将 num 除以 denom 时,我添加了从 int 到 float 的转换。
    3. 根据definition of the approximation,输入x 是弧度。所以我添加了从度数到弧度的转换。 x = x / 180.0 * math.pi;
    4. calcCosFact 中的索引错误。它总是高出 2。(即 4 而不是 2,8 而不是 6...)

    我得到了这个结果: 输入角度(以度为单位):180 输入要使用的术语数:5 cos:-0.976022212624,窦:0.00692527070751

    现在应该是正确的。当你需要快速做一些数学运算时,我也可以推荐WolphramAlpha

    【讨论】:

      【解决方案3】:

      这是一个改进的版本:

      from math import radians
      import sys
      
      # version compatibility shim
      if sys.hexversion < 0x3000000:
          # Python 2.x
          inp = raw_input
          rng = xrange
      else:
          # Python 3.x
          inp = input
          rng = range
      
      def type_getter(type):
          def fn(prompt):
              while True:
                  try:
                      return type(inp(prompt))
                  except ValueError:
                      pass
          return fn
      get_float = type_getter(float)
      get_int   = type_getter(int)
      
      def calc_sin(theta, terms):
          # term 0
          num    = theta
          denom  = 1
          approx = num / denom
          # following terms
          for n in rng(1, terms):
              num *= -theta * theta
              denom *= (2*n) * (2*n + 1)
              # running sum
              approx += num / denom
          return approx
      
      def calc_cos(theta, terms):
          # term 0
          num    = 1.
          denom  = 1
          approx = num / denom
          # following terms
          for n in rng(1, terms):
              num *= -theta * theta
              denom *= (2*n - 1) * (2*n)
              # running sum
              approx += num / denom
          return approx
      
      def main():
          print(
              "\nProgram to approximate sin and cos."
              "\nYou will be asked to enter an angle and"
              "\na number of terms."
          )
      
          theta = get_float("Enter an angle (in degrees): ")
          terms = get_int  ("Number of terms to use: ")
      
          print("sin({}) = {}".format(theta, calc_sin(radians(theta), terms)))
          print("cos({}) = {}".format(theta, calc_cos(radians(theta), terms)))
      
      if __name__=="__main__":
          main()
      

      请注意,由于 Maclaurin 级数以 x=0 为中心,因此接近 0 的 theta 值会收敛得更快:calc_sin(radians(-90), 5) 是 -1.00000354258,但 calc_sin(radians(270), 5) 是 -0.444365928238(距离正确值大约 157,000 倍) -1.0)。

      【讨论】:

        【解决方案4】:

        通过使用和组合阶乘和整数幂的递归定义,可以完全避免所有幂和阶乘计算。通过同时计算 cos 和 sin 值获得进一步优化,因此只计算一次幂。

        PI = 3.1415926535897932384;
        
        RadInDeg=PI/180;
        
        def getCosSin(x, n):
            mxx = -x*x; 
            term = 1;
            k = 2;
            cossum = 1;
            sinsum = 1;
            for i in range(n):
                term *= mxx
                term /= k; k+=1
                cossum += term
                term /= k; k+=1
                sinsum += term
            return cossum, x*sinsum
        
        def main():
            print "\nProgram to approximate sin and cos."
            print "You will be asked to enter an angle and \na number of terms."
        
        
            x = int(input("Enter an angle (in degrees): "))
            terms = int(input("Enter the number of terms to use: "))
            print 
        
            x = x*RadInDeg;
        
            cosx, sinx = getCosSin(x,terms) 
        
            print cosx, sinx
        
        if __name__=="__main__":
            main()
        

        【讨论】:

          猜你喜欢
          • 2011-02-20
          • 1970-01-01
          • 1970-01-01
          • 2014-11-19
          • 2016-06-16
          • 1970-01-01
          • 1970-01-01
          • 2017-10-06
          • 2017-12-12
          相关资源
          最近更新 更多