C# Taylor sorok?
Egyik haverom azt a házit kapta, hogy programozzon egy cosinus számítót a Taylor sorok alapján. Mondtam neki egy megoldást így hirtelen felindulásból, de nem minden számra működik. Arra tippelek, hogy a faktoriálisok miatt pár tíz faktoriális után a számok mérete túllépi a double értéktartományát. Viszont a feladat szerint milliókig ki kell számoltatni a tagok értékét. Milyen változó típust használhatnék, vagy hogy lehetne ezt áthidalni?
eddig jutottam:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
double eredmeny=0;
double a=Convert.ToDouble(Console.ReadLine());
for (int i = 0; Math.Abs(tag(i, a)) > 0.000001; i++)
{
eredmeny = eredmeny + tag(i, a);
}
Console.WriteLine("{0}", eredmeny);
}
static double faktor(double x)
{
double fakt=1;
x = x*2;
for (int j = 2; j <= x; j++)
{ fakt = fakt * j; }
return fakt;
}
static double tag(double y,double szog)
{
double t;
t = (Math.Pow((-1), y))*Math.Pow(szog,2*y)/faktor(y);
return t;
}
}
}





Én a helyedben double-t használnék, felesleges szívni, inkább használd a Stirling-formulát:
Ezzel nézd meg. Mondjuk kis értékeknél (<20) ez nem túl korrekt.
Megoldás lehet, hogy valameddig az egzakt formulával számolsz, utána meg a (korrigált) Stirlinggel . Magyarul ketté szeded a ciklusodat. Ha jól tudom (64-biten) 10^308 körüli számokat lehet megjeleníteni double esetén, ez kb. 170!-nak felel meg (170! = 7.257E306). Megnéztem a Wikipédián a Nemes Gergő-féle két módszert: ott a relatív eltérés a közelítés és az egzakt között 1.112E-13, a másodiknál 8.903E-14, ami szerintem már elfogadható :D A sima Stirlingnek elég nagy a relatív hibája (4.901E-4), azt láttam.










Ez utóbbi valóban igaz, erre nem is gondoltam hirtelenjében. De itt is lehet trükközni pár dologgal, hogy a hatványozás ne szálljon el:
1) periodicitás, ekkor (-pi,pi]-re tudod szűkíteni a teljes számegyenest.
Magyarul képezd x' = mod(x,2*pi) értéket. ha x'>pi, akkor x' -= 2*pi kell.
2) paritás kihasználása [cos(x)==cos(-x)], ekkor [0,pi]-re
x'' = abs(x')
3) eltolási azonosságokkal:
cos(x) = -cos(pi-x)
cos(x) = sin(pi/2-x)
Ekkor kell egy intervallumvizsgálat, hogy eldöntsd, melyik szögfüggvényt érdemes használni:
if (x>=0 && x<pi/4){
t = cosTS(x);
}elseif (x>=pi/4 && x<3*pi/4)
t = sinTS(pi/2-x);
}elseif (x>=3*pi/4 && x<=pi){
t = -cosTS(pi-x);
}else{
printf("Valamit elbaktam!");
}
ahol cosTS és sinTS a Taylor-sort előállító függvények, x a [0,pi]-re leképzett szög.
Tehát át tudod transzformálni x∈(-inf;inf)-et egy X∈[0,pi/4] tartományba, aminek minden eleme kisebb, mint 1. Ez azért jó, mert X^(2n) sorozat konvergens (-> 0) lesz. Tehát megadhatsz bármekkora n-et. Az persze más kérdés, hogy ha n túl nagy, a sor n-edik tagja a számábrázolás miatt 0 lesz, de ez a tag már úgy sem érdekes, hiszen nagyon kicsi (64-bites double esetén 1E-308 alatt, azt hiszem).
Megj.: Mondjuk érdemes még a Lagrange-féle maradéktagot (1E-6) kiemelni a kódból (pl. az elején adni értéket, vagy kívülről adni értéket), hogy flexibilisebb, átláthatóbb stb. legyen a kód, de ez már csak kozmetikai dolog.





Elvileg amit írtam legutóbb, azt egyszerű függvényekkel meg lehet csinálni (for és while ciklus, if-else, meg hatványozás).
[A cosTS meg a sinTS azok saját függvényeid, ahol a Taylor-sorok szerint összegzel egy while-ciklusban.]
Ha a maradéktag 1E-6 körüli, akkor nem kell még Stirling-formula sem, hanem elemi módon, for-ciklussal meg lehet oldani a faktorizálást. Persze ehhez kell, hogy x^n divergens legyen (így lesz a maradéktag is divergens), tehát az intervallum-transzformációt szerintem nem lehet megúszni (De ez is elemi dolog, while-ciklus, kivonás és if-else).
A feladatban szerintem az a kihívás (amiatt nem csak egy while-ciklus az egész), hogy rá kell jönni, hogy ha a konvergenciasugáron kívül vagyunk (|x| >= 1), nem működik a sorfejtés.
Kapcsolódó kérdések:
Minden jog fenntartva © 2025, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!