Implementacja cos(x)

0

Hej,

do napisania mam program obliczający wartość funkcji cos dla argumentu x wczytywanego z klawiatury.
Obliczanie powinno odbywać się poprzez sumowanie szeregu.

Sumowanie powinno zakończyć się gdy kolejny wyraz sumy ma moduł mniejszy niż wybrana precyzja obliczeń.

rozumiem, że taką funckę można przedstawić w postaci:

screenshot-20230503103838.png

wiem jak wykonać rekuperację i stworzyłem sobie już taki fragment kodu

        static long Factorial(int x)
        {
            long y = x;
            for (int i = x - 1; i > 1; i--)
            {
                y = y * i;
            }

            return y;
        }
        
        //static int Factorial(int x)
        //{
        //    if (x == 0)
        //        return 1;
        //    return x * Factorial(x - 1);
        //}

Z góry dziękuję za porady/wskazówki

1

Prawdopodobnie coś w tym stylu:

float prec = 0.01f;
float wyraz = 1;
float suma = 0;
int i = 1;

while (wyraz < prec)
{
    suma += wyraz;
    wyraz = Power(x, i * 2) / Factorial(i * 2);
    i++;
}

// return suma;

Dobrze by było zamknąć w funkcję, aby móc sparametryzować x oraz prec(yzję).

Tylko pewnie Power() (potęgowanie) też musisz samemu napisać, jeżeli to jakieś proste zadanko na studia.

wiem jak wykonać rekuperację i stworzyłem sobie już taki fragment kodu

Jeżeli chodziło ci o rekurencję, to ten odkomentowany fragment kodu jej nie wykorzystuje.

0
Ktos napisał(a):
 private static void Main(string[] args)
    {
        Console.WriteLine("Podaj liczbę do obliczenia:");

        float x = float.Parse(Console.ReadLine());

        var result = Cos(x);

        Console.WriteLine(result );


        static float Cos(float x)
        {
            float prec = 20;
            float expression = 1;
            float sum = 0;
            int i = 1;

            while (expression < prec)
            {
                sum += expression;
                expression = ((float)(Power(x, i * 2) / Factorial(i * 2)));
                i++;
            }

            return sum;
        }


        static float Power(float x, float y)
        {

            return (float)Math.Pow(x, y);
        }


        static double Factorial(double x)
        {
            double y = x;
            for (double i = x - 1; i > 1; i--)
            {
                y = y * i;
            }

            return y;
        }
    }

Jestem na takim etape, ale nie chodziło chyba o to, wskazany wzór
screenshot-20230503121110.png
nie odpowiada temu co mam w metodzie Cos

0

Jeżeli funkcja oblicza zły wynik, to sprawdź osobno prawidłowość obliczania potęgi i silni w poszczególnych składnikach sumy. Do tego celu najprościej wykorzystać arkusz kalkulacyjny.

W oczy rzuca się to, że w funkcji Factorial jest iteracja po liczbie zmiennoprzecinkowej. Moim zdaniem stwarza to ryzyko błędu spowodowanego reprezentacją liczb w komputerze i ta funkcja powinna wyglądać tak:

        static double Factorial(double x)
        {
            double y = x;
            for (int i = (int)x - 1; i > 1; i--)
            {
                double i_ = i;
                y = y * i_;
            }

            return y;
        }

Chodzi o to, żeby była iteracja po liczbie stałoprzecinkowej, ale do obliczeń wykorzystywana wartość licznika w postaci zmiennoprzecinkowej.

0

Stworzyłem teraz coś takiego. Mam nadzieję, że jest to bliskie wzorowi:
screenshot-20230503132240.png

 private static void Main(string[] args)
    {
        Console.WriteLine("Podaj liczbę do obliczenia:");

        float x = float.Parse(Console.ReadLine());

        Console.WriteLine("Podaj liczbę dokładności:");

        int prec = int.Parse(Console.ReadLine());

        var result = Cos(x, prec);

        Console.WriteLine(result);


        static float Cos(float x, int prec)
        {
            float sum = 0;
            float result = 0;



            for (int i = 1; i <= prec; i++)
            {
                if (i%2==0)
                {
                    result -= (float)(Power(x, i * 2) / Factorial(i * 2));
                }
                else
                {
                    result += (float)(Power(x, i * 2) / Factorial(i * 2));
                }
            }

                sum = 1 + result;

            

            return sum;
        }


        static float Power(float x, float y)
        {

            return (float)Math.Pow(x, y);
        }


        static double Factorial(double x)
        {
            double y = x;
            for (double i = x - 1; i > 1; i--)
            {
                y *= i;
            }

            return y;
        }
    }
0

Pierwszy składnik jest równy (x^0)/0!, który też jest równy 1. Warto to uwzględnić w pętli zamiast osobno dodawać 1. W tym przypadku należy przyjąć, że 0^0=1.

Jak już napisałem, proponuję obliczyć 5 pierwszych składników w arkuszu kalkulacyjnym (osobno licznik, osobno mianownik i wartość całego składnika), zsumować je, a potem obliczyć 5 pierwszych składników za pomocą tego programu. Jeżeli będzie różnica, to będzie łatwo stwierdzić, co jest nie tak, w programie warto dopisać wyświetlanie wartości poszczególnych składników w celu testowania.

0

Po kilku modyfikacjach. Program liczy prawidłowo. Testowałem do 4-ch powturzeń

 private static void Main(string[] args)
    {
        Console.WriteLine("Podaj liczbę do obliczenia:");

        float x = float.Parse(Console.ReadLine()); // liczba do przeliczenia

        Console.WriteLine("Podaj liczbę dokładności:");

        int prec = int.Parse(Console.ReadLine()); // ilosć pętli do wykonania

        var result = Cos(x, prec);

        Console.WriteLine(result);


        static float Cos(float x, int prec)
        {
            float sum = 0;
            float result = 0;



            for (int i = 1; i <= prec; i++)
            {
                if (i%2==0)
                {
                    result += (float)(Power(x, i * 2) / Factorial(i * 2));
                }
                else// if(i>1)
                {
                    result -= (float)(Power(x, i * 2) / Factorial(i * 2));
                }
            }

                sum = 1 + result;

            

            return sum;
        }


        static float Power(float x, float y)
        {
            var result = (float)Math.Pow(x, y);
            return result;
        }

        static double Factorial(double x)
        {
            double y = x;
            for (double i = x - 1; i > 1; i--)
            {
                y *= i;
            }

            return y;
        }
1

Wszystkie przykłady wyżej są niewydajne w tym sensie, że liczą potęgę i silnię za każdym razem od zera jedynki.
O ile w przypadku potęgi to może nie mieć znaczenia, to z silnią na pewno ma.
Przecież wystarczy poprzednio wyliczoną silnię pomnożyć przez dwie kolejne liczby naturalne.

1 użytkowników online, w tym zalogowanych: 0, gości: 1