Ir ao conteúdo

Posts recomendados

Postado

Então eu estou com dificuldade de encontrar onde eu errei nesse exercício. Já fui atrás de formulas e resoluções, mas nada que me fizesse entender como de fato funciona o código. Se poderem me ajudar ficarei grato.

Exercício: Faça uma função que receba como parâmetro o valor de um ângulo em graus e calcule o valor do seno desse ângulo usando a sua respectiva série de Taylor:

1816587574_WhatsAppImage2022-05-25at13_33_47.thumb.jpeg.deae3f66095e9f7cda8a9949e4918345.jpeg

em que x é o valor do ângulo em radianos. Considere pi = 3.1414952 e N variando de 0 até 5

 

Segue a baixo o meu código.

(Estou aprendendo funções)

 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
const float pi = 3.1414592;
int fatorial(int num_fat){
    int k, fat = 1;
    for(k = 1; k <= num_fat; k++){
        fat *= k;
    }
    return fat;
}
float calculo_seno(float rad){
    int i;
    float seno = 0;
    for(i = 1; i <= 5; i++){
        seno += rad - (pow(rad,i)/fatorial(i));
    }
    return seno;
}

int main(){

    float angulo_rad, seno_ang;
    printf("Entre com o valor de um ângulo: ");
    scanf("%f",&angulo_rad);
    angulo_rad = (pi*angulo_rad)/180;
    seno_ang = calculo_seno(angulo_rad);


    printf("Valor do seno = %f\n", seno_ang);
    return 0;
}

 

Postado

@beggarjs O fatorial deve ser só dos ímpares da sequencia e não do contador como fez. Para isso veja que a série tem 2n + 1 (n é o contador), o mesmo vale para o expoente do numerador. Além disso é preciso inverter o sinal na soma dos termos a cada loop.

  • Obrigado 1
Postado
30 minutos atrás, Midori disse:

@beggarjs O fatorial deve ser só dos ímpares da sequencia e não do contador como fez. Para isso veja que a série tem 2n + 1 (n é o contador), o mesmo vale para o expoente do numerador. Além disso é preciso inverter o sinal na soma dos termos a cada loop.

Obrigado, não prestei a devida atenção no enunciado.

A parte do contador eu acredito que consiga fazer sim, porém a parte dos sinais eu já não sei ao certo como posso fazer. Seria só multiplicar por -1?

Postado

@beggarjs Para inverter o sinal você pode fazer como está na série, multiplicando a soma por -1 elevado ao contador. Ou pode multiplicar por uma variável iniciada com 1 e que inverte o sinal no loop, p.ex: variavel = -variavel.

  • Obrigado 1
Postado
18 minutos atrás, Midori disse:

@beggarjs Para inverter o sinal você pode fazer como está na série, multiplicando a soma por -1 elevado ao contador. Ou pode multiplicar por uma variável iniciada com 1 e que inverte o sinal no loop, p.ex: variavel = -variavel.

Ótimo vou trabalhar na resolução e mostro o resultado aqui depois. Obrigado.

Postado

@Midori Olá, ainda estou com dificuldade de entender, porém acho que cheguei em um resultado.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
const float pi = 3.1414592;
int fatorial(int num_fat){
    int i, fat_func = 1;
    for(i = 1; i <= num_fat; i++){
        fat_func *= i;
    }
    return fat_func;
}
double calc_seno(double x){
    int n, exp = 3;
    double seno_func = 0;
    for(n = 0; n < 5; n++){
        seno_func += pow(-1.0, n)*pow(x, 2*n+1)/fatorial(2*n+1);
    }
    return seno_func;
}

int main(){

    double angulo, seno, radianos;

    printf("Digite o valor de um ângulo em graus: ");
    scanf("%lf",&angulo);

    radianos = (pi*angulo)/180;
    seno = calc_seno(radianos);
    
    printf("Seno %lf\n",seno);

    return 0;
}

Eu fiz os testes usando a calculadora e a principio ele ta retornando o valor certo. encontrei muitas resoluções na internet porém eram com o seno do angulo e não do radiando. Enfim, saberia me dizer se agora está correto? 

 

Postado
6 horas atrás, beggarjs disse:

Então eu estou com dificuldade de encontrar onde eu errei nesse exercício. Já fui atrás de formulas e resoluções, mas nada que me fizesse entender como de fato funciona o código. Se poderem me ajudar ficarei grato.

Exercício: Faça uma função que receba como parâmetro o valor de um ângulo em graus e calcule o valor do seno desse ângulo usando a sua respectiva série de Taylor:

 

Escreva em torno dos dados. E use um papel antes de um programa nesse caso.

 

Resumo dos dados: a série de Taylor com 6 termos. Só isso.

 

Resumo do objetivo: aproximar sen(x) usando a série.

 

E está aprendendo funções.

 

Não precisa resolver tudo ou escrever uma série genérica para n termos. Só vai usar 5. E do modo como está escrito nem adianta porque o fatorial de um inteiro não vai muito longe e logo ia ter que aproximar o fatorial para aproximar o valor das parcelas na série 🙂 

 

E porque não colocou o seno aproximado pela própria função de math.h para ver sua série se aproximando (ou não 🙂 ) ? Assim saberia se está funcionando

 

Os tais 6 termos: já tem 3 na imagem que mostrou, Porque não acrescentou os outros 3 e tirou a somatória de lá?

 

A Somatória

 

image.png.32099b172866cb99c06b768853af16da.png

Cada termo da série é isso.

  • o numerador alterna entre 1 e -1 então o sinal das parcelas vai alternar
  • 2n+1 é ímpar para todo n
  • n vai de 0 a 5 inclusive então vai ter 1,3,5,7,9 e 11

E é só isso. Provavelmente seria melhor escrever

 

image.png.ef3fad2385b915067c3a211be76aa503.png

para ver a progressão dos termos melhor e entender que o primeiro fator apenas alterna o sinal.

 

 

 

Então juntando os outros 3 termos aos 3 que já tem lá:
 

image.png.0ff02b601fcf9b1e77863caa7ed04849.png

 

E é isso que tem que calcular. Somar.

 

 

Claro que tem muitas e muitas maneiras de fazer isso, mas olhando para a série dá pra ver na hora que cada termo é o anterior multiplicado por x ao quadrado e dividido por (2n+1)*(2n), onde x é o grau em radianos e n é a posição da parcela na série, de 0 a 5 inclusive.

 

Citação

Nem precisa do fatorial, como se vê.

 

Função em C

 

Uma função em C é um bloco de código com um nominho. E ao ser executada retorna algo, ou nada, no caso de retornar void.

 

Função fatorial para esse caso

 

fatorial não vai muito longe em C com int porque o fatorial cresce muito rápido e um int tem no máximo 10 dígitos --- e o primeiro é 2: a saber INT_MAX que é 2.147.483.657

 

Veja esse complexo programa de 1 linha:
 


#include <limits.h>
#include <stdio.h>
int main(void)
{
    for ( int f=1,i = 1; (INT_MAX/f > i); i+=1)
    {
        f = f * i;
        printf("i = %2d f = %12d MAX %12d\n", i, f, INT_MAX/f);
    }
}

 

que mostra o tal valor

 

i =  1 f =            1 MAX   2147483647
i =  2 f =            2 MAX   1073741823
i =  3 f =            6 MAX    357913941
i =  4 f =           24 MAX     89478485
i =  5 f =          120 MAX     17895697
i =  6 f =          720 MAX      2982616
i =  7 f =         5040 MAX       426088
i =  8 f =        40320 MAX        53261
i =  9 f =       362880 MAX         5917
i = 10 f =      3628800 MAX          591
i = 11 f =     39916800 MAX           53
i = 12 f =    479001600 MAX            4

 

pois é: 12! é o maior que cabe. Depois já era. E SEMPRE vai dar o mesmo resultado então vamos economizar carbono e aceitar a realidade: só cabe até 12! em um int. E os valores são bem conhecidos, sempre os mesmos. Podiam quem sabe estar numa lista? Ou será que é melhor calcular de novo a vida toda? Não, não é.

 

Mudando o programa de 1 linha acima:

 

#include <limits.h>
#include <stdio.h>
int main(void)
{
    for ( int f=1,i = 1; i<13; i+=1)
        f = f * i, printf("%10d,\n", f);
}

 

Ele mostra

 

         1,         2,         6,        24,       120,
         720,      5040,     40320,    362880,   3628800,
         39916800, 479001600,

 

São os valores de 1! a 12! certo? Tudo em uma linha só. 0! = 1 então usando copiar e colar tem a tabela dos 13 números. válida por toda a eternidade.
 

int fatorial(int n)
{
    const int tab[13] = {
           1,     1,     2,     6,      24,      120,
         720,  5040, 40320, 362880, 3628800, 39916800,
         479001600
    };
    if ((n > 12) || (n < 0)) return -1;
    return tab[n];
}

 

Testar? Um novo programa de uma linha chamando a função fatorial() afinal estamos aprendendo função.
 

#include <limits.h>
#include <stdio.h>
int fatorial(int);
int main(void)
{
    for ( int i = 0; i<13; i+=1)
        printf("%4d!=%d\n", i,fatorial(i));
}

int fatorial(int n)
{
    const int tab[13] = {
           1,     1,     2,     6,      24,      120,
         720,  5040, 40320, 362880, 3628800, 39916800,
         479001600
    };
    if ((n > 12) || (n < 0)) return -1;
    return tab[n];
}

 

mostra

 

   0!=1
   1!=1
   2!=2
   3!=6
   4!=24
   5!=120
   6!=720
   7!=5040
   8!=40320
   9!=362880
  10!=3628800
  11!=39916800
  12!=479001600

 

E é só comparar com a lista. Tudo certo com o fatorial. E isso deve ser dezenas e dezenas de vezes mais rápido que o código original.

 

De volta à somatória, a tal série de Taylor. Quanto vale o primeiro termo? x. Está claro lá. E os outros termos? A cada vez basta multiplicar por x*x e dividir por (2n+1) *2n. Nem precisa do fatorial, certo?

 

seja uma função taylor()

 

	double taylor(double x)


que a cada vez que você chamar devolva a tal soma em um double. 

 

Se você chamar 6 vezes terá o resultado que quer. A cada vez que chama podia mostrar o seno retornado por sin() só para ficar mais seguro de que a série está convergindo para o tal valor...

 

Algo assim 
 

      for( int n=0;n<6;n+=1) printf("taylor(%.4f) = %10.9f "
          "sin(%.4f) = %.4f\n",
          g60,taylor(g60), // calculado pela funcao
          g60,sin(g60)); // calculado por sin()

 

Mais uma vez uma linha só, na verdade.

 

E o código?

 

double taylor(double x)
{
    static int n = 0;
    static int fator = -1;
    static double den = 1.;
    static double num = 1.;
    static double termo = 0.;
    if ( n == 0 )
    {   n = 1;
        termo = num = x;
        return x;
    };
    num = x * x * num;
    den = den * (n+n+1) * (n+n);
    termo += num / den * fator;
    fator = -fator;
    n +=1;
    return termo;
};

 

Podia ser algo assim. Copiado da fórmula, calcula o numerador e o denominador e acumula na soma.

 

Um teste para um ângulo de 30 graus
 

taylor(0.5236) = 0.523598727 sin(0.5236) = 0.5000
taylor(0.5236) = 0.499674137 sin(0.5236) = 0.5000
taylor(0.5236) = 0.500002090 sin(0.5236) = 0.5000
taylor(0.5236) = 0.499999949 sin(0.5236) = 0.5000
taylor(0.5236) = 0.499999958 sin(0.5236) = 0.5000
taylor(0.5236) = 0.499999958 sin(0.5236) = 0.5000

 

E um de 90
 

taylor(1.5708) = 1.570796180 sin(1.5708) = 1.0000
taylor(1.5708) = 0.924832264 sin(1.5708) = 1.0000
taylor(1.5708) = 1.004524853 sin(1.5708) = 1.0000
taylor(1.5708) = 0.999843102 sin(1.5708) = 1.0000
taylor(1.5708) = 1.000003543 sin(1.5708) = 1.0000
taylor(1.5708) = 0.999999944 sin(1.5708) = 1.0000

 

Nada mal: mais de 6 dígitos de precisão em apenas 6 termos.

 

Um programa inteiro

juntando as linhas
 


#include <limits.h>
#include <math.h>
#include <stdio.h>
double taylor(double);
double main(void)
{
    double g60 = 3.14159236 / 2; // 90
    for( int n=0;n<6;n+=1) printf("taylor(%.4f) = %10.9f "
        "sin(%.4f) = %.4f\n",
        g60,taylor(g60),g60,sin(g60));
}

double taylor(double x)
{
    static int n = 0;
    static int fator = -1;
    static double den = 1.;
    static double num = 1.;
    static double termo = 0.;
    if ( n == 0 )
    {   n = 1;
        termo = num = x;
        return x;
    };
    num = x * x * num;
    den = den * (n+n+1) * (n+n);
    termo += num / den * fator;
    fator = -fator;
    n +=1;
    return termo;
};

 

 

 

56 minutos atrás, beggarjs disse:

Eu fiz os testes usando a calculadora e a principio ele ta retornando o valor certo. encontrei muitas resoluções na internet porém eram com o seno do angulo e não do radiando. Enfim, saberia me dizer se agora está correto?

 

Sugiro o simples: coloque ao lado do valor o valor de sin() para o ângulo. E porque não mostrar a diferença? 

 

veja o meu exemplo 

  • Obrigado 1
Postado

@arfneto Obrigado por essa explicação completa.

Não tinha conhecimento do sin() para fazer os testes, no livro ele não é muito abordado.

mas vai ser de grande ajuda agora. Obrigado de verdade por sua ajuda.

 

edit: fiz o teste usando sin() e passei longe de acertar. Vou recomeçar.

Postado
34 minutos atrás, beggarjs disse:

edit: fiz o teste usando sin() e passei longe de acertar. Vou recomeçar.

 

veja a soma que mostrei. nem precisa de fatorial. Basta usar em uma função que faz o loop e terá o seno.

 

Eu mostrei passo a passo só para ilustrar. É um forum afinal. Mas não precisa. Cada parcela é determinada: multiplica por x*x e divide por 4*n*n + n+n certo?  E vai invertendo o sinal e a soma converge muito rápido para o seno.

 

 

  • Obrigado 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...