Problema con el progtwig para aproximar los valores de pecado y coseno

Estoy tratando de escribir un progtwig que tome un ángulo en grados y se aproxime al valor de sin y cos en función de una serie de términos dados que el usuario elige. En caso de no saber encontrar el pecado y el cos. Entonces, con eso dicho, aquí está mi código actual:

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 

Funciona pero si uso el ejemplo que se muestra en la imagen de arriba, obtengo cos = -162527117141.85715 y sin = -881660636823.117. Así que claramente algo está apagado. En la imagen de arriba, las respuestas deben ser cos = 0.50000000433433 y sin = 0.866025445100. Supongo que es la forma en que estoy sumndo los valores en el primer bucle, pero podría estar equivocado. Cualquier ayuda es apreciada!

Hay varios problemas aquí como se señala en los comentarios de Russell Borogove .

El problema no 1 es que las fórmulas que estás usando

introduzca la descripción de la imagen aquí

(ver wikipedia ) espera que x esté en radianes, no en grados. Ir una vez alrededor de un círculo es de 360 ​​grados o 2 * pi, por lo que puede convertir de grados a radianes multiplicando por pi / 180, como se muestra a continuación en el código de Python para obtener el pecado de 90 grados.

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

El número 2 es el rest del código. Como se señaló en los comentarios, hay algunos errores, y la mejor manera de encontrarlos sería usar algunas declaraciones de print estratégicas. Sin embargo, podría escribir su progtwig con muchas menos líneas de código, y los progtwigs más simples tienden a tener menos errores y serán más fáciles de depurar si tienen problemas.

Como esta es una tarea, no lo haré por ti, pero un ejemplo relacionado es la serie para sinh (x).

introduzca la descripción de la imagen aquí

(de nuevo de wikipedia)

Puede producir los términos en “una sola toma”, usando una comprensión de la lista de Python. La lista se puede print y sum med para obtener el resultado, como en el siguiente progtwig

 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) 

La salida de este progtwig es

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

Produje el código de comprensión de la lista de Python directamente de la fórmula matemática para la sum, que se proporciona convenientemente en la notación “Sigma” en el lado izquierdo. Puedes producir pecado y cos de una manera similar. El único ingrediente que falta es los signos en cada punto de la serie. Las fórmulas matemáticas te dicen que necesitas (-1) n . El equivalente de Python es (-1)**n , que se puede ubicar en el lugar apropiado en el código de comprensión de la lista.

Primero, unas pocas notas. Es mejor imprimir \n al final de la impresión anterior o al principio de la siguiente, luego print() vacío print() . Es útil usar una herramienta de depuración, usar el módulo de logging o simplemente usar print y encontrar el error comparando los valores esperados con los valores devueltos.

Aquí hay un código que me funciona:

 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 

¿Y qué he cambiado? (Espero no olvidar nada)

  1. Sus variables de sign estaban mal. Justo lo contrario. Así que cambié las señales en las condiciones.
  2. Quizás no sea necesario, pero agregué la conversión de int a float cuando denom num por denom .
  3. Según la definición de la aproximación , la entrada x está en radianes. Así que agregué la conversión de grados a radianes. x = x / 180.0 * math.pi;
  4. Tu índice en calcCosFact estaba equivocado. Siempre fue mayor en 2. (es decir, 4 en lugar de 2, 8 en lugar de 6 …)

Obtuve este resultado: Ingrese un ángulo (en grados): 180 Ingrese el número de términos a usar: 5 Cos: -0.976022212624, Sinus: 0.00692527070751

Debe ser correcto ahora. También puedo recomendar WolphramAlpha cuando necesites hacer algunos cálculos rápidamente.

Aquí hay una versión mejorada:

 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() 

Tenga en cuenta que debido a que la serie Maclaurin está centrada en x = 0, los valores de theta más cercanos a 0 convergerán mucho más rápido: calc_sin(radians(-90), 5) es -1.00000354258 pero calc_sin(radians(270), 5) es -0.444365928238 (aproximadamente 157,000 veces más lejos del valor correcto de -1.0).

Se pueden evitar por completo todos los cálculos de poder y factoriales utilizando y combinando las definiciones recursivas de los poderes factoriales y enteros. Se obtiene una optimización adicional calculando los valores de cos y sin a la vez, de modo que las potencias solo se calculan una vez.

 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()