Jak mohu přepsat následující pseudokód v C ++?
real array sine_table[-1000..1000]
for x from -1000 to 1000
sine_table[x] := sine(pi * x / 1000)
Musím vytvořit sine_table vyhledávací tabulku.
Jak mohu přepsat následující pseudokód v C ++?
real array sine_table[-1000..1000]
for x from -1000 to 1000
sine_table[x] := sine(pi * x / 1000)
Musím vytvořit sine_table vyhledávací tabulku.
Budete chtít std::sin()funkci z <cmath>.
long double sine_table[2001];
for (int index = 0; index < 2001; index++)
{
sine_table[index] = std::sin(PI * (index - 1000) / 1000.0);
}
double table[1000] = {0};
for (int i = 1; i <= 1000; i++)
{
sine_table[i-1] = std::sin(PI * i/ 1000.0);
}
double getSineValue(int multipleOfPi){
if(multipleOfPi == 0) return 0.0;
int sign = 1;
if(multipleOfPi < 0){
sign = -1;
}
return signsine_table[signmultipleOfPi - 1];
}
Můžete zkrátit délku pole až 500, o trik sin (pi / 2 +/- úhel) = +/- cos (angle). Takže obchod sin a cos od 0 do pi / 4. Nepamatuji si z vrcholu mé hlavy, ale zvýšila rychlost mého programu.
Můžete snížit velikost svého stolu na 25% původní pouze o ukládání hodnot na prvním kvadrantu, tj x v [0, pi / 2].
Chcete-li, že vaše vyhledávací rutina prostě musí mapovat všechny hodnoty x na prvním kvadrantu pomocí jednoduchých Trig identity:
Mapovat z kvadrantu III I použít obě identity, tj sin (x) = - sin (PI + x)
Zda je tato strategie pomáhá závisí na tom, kolik otázek využití paměti ve vašem případě. Ale zdá se, nehospodárné uložit čtyřikrát tolik hodnoty jako je třeba jen proto, aby se zabránilo srovnávání a odčítání nebo dva v průběhu vyhledávání.
I druhý Jeremyho doporučení zjišťovat, zda stavět tabulku, je lepší, než jen s použitím std :: sin (). Dokonce s původním velkého stolu, budete muset strávit cyklů během každé vyhledávací tabulku převést argument k nejbližšímu přírůstek pi / 1000, a ztratíte trochu přesnosti v tomto procesu.
Pokud jste opravdu snaží obchodovat přesnost pro rychlost, můžete zkusit sbližování funkci sin () pomocí jen několik prvních členů řady expanzi Taylora.
Samozřejmě, že pro účinnost, je třeba při výpočtu x ^ 5 precompute faktoriálů a využívat nižších síly x počítat ve vyšších polohách, například použití x ^ 3.
Poslední bod, zkrácený Taylorova řada výše je přesnější pro hodnoty blíže k nule, takže je stále ještě stojí k mapování na první nebo čtvrtého kvadrantu před výpočtu přibližné sinus.
Dodatek: Ještě jedna další potenciál ke zlepšení na základě dvou připomínek:
1. Můžete vypočítat libovolnou funkci Spouštěč pokud můžete spočítat i sin a cos v prvním oktantu [0, pi / 4]
2. Expanze Taylorova řada se středem na nule je přesnější téměř nulová
Takže pokud jste se rozhodli použít zkrácený Taylorovy řady, pak si můžete zlepšit přesnost (nebo použít méně podmínky pro podobnou přesností) mapováním buď sinus nebo cosinus dostat úhel v rozsahu [0, pi / 4] pomocí identity, jako je sin (x) = cos (pi / 2 x) a cos (x) = sin (pi / 2 x), kromě těch výše (například je-li x> pi / 4, jakmile jste mapované do první kvadrant).
Nebo pokud se rozhodnete použít vyhledávací tabulku pro sin a cos, mohli byste dostat se dvěma menšími tabulkami, které se vztahovalo pouze na rozsah [0, pi / 4] na úkor dalšího možného porovnávání a odčítání na vyhledávání mapovat menší rozsah. Pak byste mohli použít buď méně paměti pro tabulky, nebo použít stejnou paměť, ale poskytují lepší rozlišovací a přesnost.
Ještě jeden bod: volání goniometrických funkcí je drahý. Chcete-li připravit vyhledávací tabulky pro sine s konstantním krokem - můžete ušetřit čas výpočtu, na úkor nějakého potenciálního přesné ztráty.
Zvážit své minimální krok je „a“. To znamená, že budete potřebovat sin (a), sin (2A), sin (3a), ...
Pak můžete provést následující trik: První výpočet sin (a) a cos (a). Pak pro každé následující krok použijte následující trigonometrické rovností:
Nevýhodou této metody je, že v průběhu tohoto postupu se akumuluje kolo-off chyba.
další aproximace z knihy nebo něco podobného
streamin ramp;
streamout sine;
float x,rect,k,i,j;
x = ramp -0.5;
rect = x * (1 - x < 0 & 2);
k = (rect + 0.42493299) *(rect -0.5) * (rect - 0.92493302) ;
i = 0.436501 + (rect * (rect + 1.05802));
j = 1.21551 + (rect * (rect - 2.0580201));
sine = i*j*k*60.252201*x;
plná diskuse zde: http://synthmaker.co.uk/forum/viewtopic.php?f=4&t=6457&st=0&sk=t&sd=a
Domnívám se, že víte, že pomocí dělení je mnohem pomalejší, než vynásobením desetinné číslo, / 5 je vždy pomalejší než 0,2 *
je to jen přibližný.
taky:
streamin ramp;
streamin x; // 1.5 = Saw 3.142 = Sin 4.5 = SawSin
streamout sine;
float saw,saw2;
saw = (ramp * 2 - 1) * x;
saw2 = saw * saw;
sine = -0.166667 + saw2 * (0.00833333 + saw2 * (-0.000198409 + saw2 * (2.7526e-006+saw2 * -2.39e-008)));
sine = saw * (1+ saw2 * sine);