The problem is that the calculation of the cosine approximation is incorrect. If you look at the Taylor series of the cosine, you'll see that the value starts with 1 - but you start the variable resultado
with 0 . Just change to resultado = 1
that (this part) will work.
There you will have another problem, related to precision. The approximation by this method generates some errors, and when the cosine results in 1 its function may return 1.00000000000001. In that case, the root you try to compute in the sine function will generate a complex number (since 1 - 1.00000000000001 will give a negative number). So another useful change is you round the return of your cosine function to some decimal places (I think 6 houses are fine).
The changed code follows below. But note that you did not prepare a working example : many of your functions are not in code. So, for testing, I've changed using the math
package. The code, by the way, compares your calculation with those of the math
package to illustrate the correctness.
import math
def converterGrausParaRad(numero):
rad = (numero/180)*math.pi
return rad
#abaixo: definição da função seno por sin² + cos² = 1
def seno(numero):
resultado = 0
resultado = math.sqrt(1 - (coseno(numero))**2)
return resultado
#abaixo:definição da função coseno pela sua expanção da serie de taylor
def coseno(rad):
numero = converterGrausParaRad(rad)
cont = 0
resultado = 1 # ERRO!!!
while(cont < 50):
cont += 1
resultado += (((-1)**cont)*(numero**(2 * cont)))/(math.factorial(2 * cont))
return round(resultado, 6) # MELHORIA
angles = [i for i in range(0, 181, 15)]
for angle in angles:
sin = seno(angle)
cos = coseno(angle)
sin_ = math.sin(converterGrausParaRad(angle))
cos_ = math.cos(converterGrausParaRad(angle))
print('ângulo: {} seno: {:.4f} ({:.4f}) cosseno: {:.4f} ({:.4f})' \
.format(angle, sin, sin_, cos, cos_))
Result:
ângulo: 0 seno: 0.0000 (0.0000) cosseno: 1.0000 (1.0000)
ângulo: 15 seno: 0.2588 (0.2588) cosseno: 0.9659 (0.9659)
ângulo: 30 seno: 0.5000 (0.5000) cosseno: 0.8660 (0.8660)
ângulo: 45 seno: 0.7071 (0.7071) cosseno: 0.7071 (0.7071)
ângulo: 60 seno: 0.8660 (0.8660) cosseno: 0.5000 (0.5000)
ângulo: 75 seno: 0.9659 (0.9659) cosseno: 0.2588 (0.2588)
ângulo: 90 seno: 1.0000 (1.0000) cosseno: 0.0000 (0.0000)
ângulo: 105 seno: 0.9659 (0.9659) cosseno: -0.2588 (-0.2588)
ângulo: 120 seno: 0.8660 (0.8660) cosseno: -0.5000 (-0.5000)
ângulo: 135 seno: 0.7071 (0.7071) cosseno: -0.7071 (-0.7071)
ângulo: 150 seno: 0.5000 (0.5000) cosseno: -0.8660 (-0.8660)
ângulo: 165 seno: 0.2588 (0.2588) cosseno: -0.9659 (-0.9659)
ângulo: 180 seno: 0.0000 (0.0000) cosseno: -1.0000 (-1.0000)
If you use the general formula (it's there on the same Wikipedia link), then need to start the factor ( cont
) at 0 (because -1 raised to 0 is 0, which is positive, and the calculation of the first interaction results in 1). Then, just move the line that adds 1 in the variable cont
to after calculating the current factor:
def coseno(rad):
numero = converterGrausParaRad(rad)
cont = 0
resultado = 0
while(cont < 50):
resultado += (((-1)**cont)*(numero**(2 * cont)))/(math.factorial(2 * cont))
cont += 1 # MOVIDO P/ APÓS O CÁLCULO
return round(resultado, 6)
Note:
Your idea of switching the signal using -1 to factor is well
intelligent. :) But keep in mind that the **
operator is computationally costly. An
suggestion that should be more efficient is to do the following (using
the power-up operator only once):
def coseno(rad):
numero = converterGrausParaRad(rad)
signal = -1
resultado = 1
factors = [i for i in range(2, 50, 2)]
for f in factors:
resultado += signal * ((numero ** f) / math.factorial(f) )
signal *= -1
return round(resultado, 6)