Calcolo Numerico: Esercitazione di Laboratorio...
Transcript of Calcolo Numerico: Esercitazione di Laboratorio...
Calcolo Numerico: Esercitazione di Laboratorio N.3
Marco Trentini [email protected]
18 febbraio 2012
Esercizio
Implementare l’algoritmo CORDIC per il calcolo delle funzioni circolari e delle funzioni iperboliche.Implementare sia la modalità ROTATION sia la modalità VECTOR (funzioni inverse). Mostrarecon un esempio che per le funzioni iperboliche è necessario ripetere ogni passo per approssimarecorrettamente l’algoritmo.
Il metodo CORDIC serve per calcolare le funzioni elementari effettuando solo addizioni, shift euna moltiplicazione. Tale metodo è molto utile quando non c’è una moltiplicazione hardware equindi è esseziale fare meno moltiplicazioni possibili. Trova impiego per esempio all’interno di al-cune calcolatrici da tavolo.
L’idea che sta alla base della modalità ROTATION è la seguente: se si ruota nel piano il vettore(1, 0) di un angolo θ, allora le coordinate del nuovo punto sono (cosθ, sinθ); la rotazione dell’angoloθ verrà effettuata con una successione di n rotazioni elementari ciascuna di costo trascurabile. Conquesta modalità è possibile calcolare le funzioni seno e coseno di un certo angolo così come le relativefunzioni trigonometriche iperboliche.
Segue il codice C della funzione che permette di calcolare il seno e coseno di un certo angolo θ
utilizzando il metodo CORDIC nella modalità ROTATION.
void cordic_r(double theta, double *sin, double *cos)
{
// compute sin and cos values by rotation method
// -1.74... =< theta in radian <= 1.74...
double k,s,a,b,c,d,e,f,g,h,l,m,appx,appy,sigma;
int i,n;
*sin=0;
*cos=1;
n=54; // rotations number
k=1;
for(i=0;i<n;i++) // compute costant k
{
a=(double)-2*i;
b=pow(2,a);
c=sqrt(1+b);
d=1/c;
k=k*d;
1
}
s=0;
for(i=0;i<n;i++) // compute rotations and sin and cos values
{
if(s>theta)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
f=atan(e);
g=sigma*f;
s=s+g; // rotation
h=sigma*e;
l=*sin * h;
appx=*cos-l;
m=*cos * h;
appy=m+*sin;
*cos=appx;
*sin=appy;
}
*sin=*sin*k; // sin value
*cos=*cos*k; // cos value
}
Per vedere qual’è il range di valori dell’angolo θ entro il quale tale funzione converge ai reali valoridi seno e coseno utilizziamo il seguente main.
// compile as gcc -I./ main.c -lm -o ex3
#include <cordic.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//check convergent values
double theta;
double cordic_sin,cordic_cos;
for(theta=-1.85;theta<1.9;theta=theta+0.01)
{
cordic_r(theta, &cordic_sin, &cordic_cos);
printf("theta %.5lf\n",theta);
printf("sin\n");
printf("cordic %.25lf\n",cordic_sin);
printf("sin() %.25lf\n",sin(theta));
printf("cos\n");
printf("cordic %.25lf\n",cordic_cos);
2
printf("cos() %.25lf\n",cos(theta));
printf("\n");
}
return 0;
}
In questo modo andiamo a confrontare i valori risultanti dalla funzione CORDIC in esame con quellidelle funzioni trigonometriche seno e coseno applicate su un certo range di angoli θ. Segue un pezzodi output rilevante.
...
...
theta -1.77000
sin
cordic -0.9851603975295764037412027
sin() -0.9802244727880454755464257
cos
cordic -0.1716362174465750622953664
cos() -0.1978888146091090094458309
theta -1.76000
sin
cordic -0.9851603975295764037412027
sin() -0.9821543171376184711007795
cos
cordic -0.1716362174465750622953664
cos() -0.1880768388928800993742385
theta -1.75000
sin
cordic -0.9851603975295764037412027
sin() -0.9839859468739369230405600
cos
cordic -0.1716362174465750622953664
cos() -0.1782460556494920855818975
theta -1.74000
sin
cordic -0.9857191788355539330268584
sin() -0.9857191788355534889376486
cos
cordic -0.1683974479490762954370098
cos() -0.1683974479490770170819758
theta -1.73000
sin
cordic -0.9873538397007167732866151
sin() -0.9873538397007164402197077
cos
cordic -0.1585320006441978124556158
cos() -0.1585320006441977569444646
theta -1.72000
sin
cordic -0.9888897660047017978968142
3
sin() -0.9888897660047014648299069
cos
cordic -0.1486507002713633451840280
cos() -0.1486507002713636504953598
...
...
theta 1.72000
sin
cordic 0.9888897660047012427853019
sin() 0.9888897660047010207406970
cos
cordic -0.1486507002713662317638921
cos() -0.1486507002713662872750433
theta 1.73000
sin
cordic 0.9873538397007164402197077
sin() 0.9873538397007159961304978
cos
cordic -0.1585320006442007267910554
cos() -0.1585320006442003937241481
theta 1.74000
sin
cordic 0.9857191788355533779153461
sin() 0.9857191788355530448484387
cos
cordic -0.1683974479490791265057226
cos() -0.1683974479490796261060837
theta 1.75000
sin
cordic 0.9851603975295764037412027
sin() 0.9839859468739364789513502
cos
cordic -0.1716362174465750622953664
cos() -0.1782460556494947223615810
theta 1.76000
sin
cordic 0.9851603975295764037412027
sin() 0.9821543171376179159892672
cos
cordic -0.1716362174465750622953664
cos() -0.1880768388928827361539220
...
...
Possiamo notare che la funzione CORDIC in esame converge con −1.74 . . . ≤ θ(radianti) ≤ 1.74 . . .ossia −99.7◦ . . . ≤ θ(gradi) ≤ 99.7◦ . . .. Oltre questo range non abbiamo una buona approssimazio-ne.
Segue il codice C della funzione che permette di calcolare il seno e coseno iperbolico di un certoangolo utilizzando il metodo CORDIC nella modalità ROTATION.
4
void cordic_rh(double theta, double *sinh, double *cosh)
{
// compute sinh and cosh values by rotation method
// -2.11... =< theta in radian <= +2.11...
double k,k2,s,a,b,c,d,e,f,g,h,l,m,appx,appy,sigma;
int i,n;
*sinh=0;
*cosh=1;
n=54;
k=1;
for(i=1;i<n;i++) // compute costant k
{
a=(double)-2*i;
b=pow(2,a);
c=sqrt(1-b);
d=1/c;
k=k*d;
}
s=0;
for(i=1;i<n;i++) // compute rotations and sin and cos values
{
if(s>theta)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
f=atanh(e);
g=sigma*f;
s=s+g; //rotation
h=sigma*e;
l=*sinh * h;
appx=*cosh+l;
m=*cosh * h;
appy=m+*sinh;
*cosh=appx;
*sinh=appy;
// repeat the step
if(s>theta)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
5
f=atanh(e);
g=sigma*f;
s=s+g;
h=sigma*e;
l=*sinh * h;
appx=*cosh+l;
m=*cosh * h;
appy=m+*sinh;
*cosh=appx;
*sinh=appy;
}
k2=k*k;
*sinh=*sinh*k2;
*cosh=*cosh*k2;
}
Per vedere qual’è il range di valori dell’angolo θ entro il quale tale funzione converge ai reali valoridel seno e coseno iperbolico utilizziamo il seguente main.
// compile as gcc -I./ main.c -lm -o ex3
#include <cordic.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//check convergent values
double theta;
double cordic_sinh,cordic_cosh;
for(theta=-2.15;theta<2.16;theta=theta+0.01)
{
cordic_rh(theta, &cordic_sinh, &cordic_cosh);
printf("theta %.5lf\n",theta);
printf("sinh\n");
printf("cordic %.25lf\n",cordic_sinh);
printf("sinh() %.25lf\n",sinh(theta));
printf("cosh\n");
printf("cordic %.25lf\n",cordic_cosh);
printf("cosh() %.25lf\n",cosh(theta));
printf("\n");
}
return 0;
}
In questo modo andiamo a confrontare i valori risultanti dalla funzione CORDIC con quelli dellefunzioni trigonometriche seno e coseno iperboliche per un particolare range di valori di θ. Segue unpezzo di output rilevante.
6
...
...
theta -2.13000
sinh
cordic -4.0674318638878332876629429
sinh() -4.1480147587938613895630624
cosh
cordic 4.1885560718904120136585334
cosh() 4.2668520526462714315130142
theta -2.12000
sinh
cordic -4.0674318638878332876629429
sinh() -4.1055529295881196816253578
cosh
cordic 4.1885560718904120136585334
cosh() 4.2255845580995767818421882
theta -2.11000
sinh
cordic -4.0635016590966506200288677
sinh() -4.0635016590966426264230904
cosh
cordic 4.1847396255300353118400380
cosh() 4.1847396255300246536990016
theta -2.10000
sinh
cordic -4.0218567421573414577551375
sinh() -4.0218567421573379050414587
cosh
cordic 4.1443131704103199908217903
cosh() 4.1443131704103199908217903
theta -2.09000
sinh
cordic -3.9806140142438106721556323
sinh() -3.9806140142438075635311634
cosh
cordic 4.1043011500612678332799987
cosh() 4.1043011500612625042094805
...
...
theta 2.09000
sinh
cordic 3.9806140142437991258361762
sinh() 3.9806140142437946849440777
cosh
cordic 4.1043011500612571751389623
cosh() 4.1043011500612500697116047
theta 2.10000
sinh
7
cordic 4.0218567421573307996141011
sinh() 4.0218567421573254705435829
cosh
cordic 4.1443131704103102208591736
cosh() 4.1443131704103075563239145
theta 2.11000
sinh
cordic 4.0635016590966390737094116
sinh() 4.0635016590966301919252146
cosh
cordic 4.1847396255300255418774213
cosh() 4.1847396255300122192011258
theta 2.12000
sinh
cordic 4.0674318638878332876629429
sinh() 4.1055529295881072471274820
cosh
cordic 4.1885560718904120136585334
cosh() 4.2255845580995634591658927
theta 2.13000
sinh
cordic 4.0674318638878332876629429
sinh() 4.1480147587938480668867669
cosh
cordic 4.1885560718904120136585334
cosh() 4.2668520526462581088367187
...
...
Possiamo notare che la funzione CORDIC in esame converge con −2.11 . . . ≤ θ(radianti) ≤ 2.11 . . .ossia −120.89◦ . . . ≤ θ(gradi) ≤ 120.89◦ . . .. Oltre questo range non abbiamo una buona approssi-mazione.
Facciamo notare che è necessario ripetere tutte le iterazioni (anche se in realtà possiamo ripe-terne solo alcune) affinchè il metodo converga in modo corretto per certi valori dell’angolo θ.Per verificarlo procediamo in questo modo: costruiamo la stessa funzione senza la ripetizione delleiterazioni.
void cordic_rh_NO(double theta, double *sinh, double *cosh)
{
// as cordic_rh without repeat the steps
double k,s,a,b,c,d,e,f,g,h,l,m,appx,appy,sigma;
int i,n;
*sinh=0;
*cosh=1;
n=54;
k=1;
8
for(i=1;i<n;i++) // compute costant k
{
a=(double)-2*i;
b=pow(2,a);
c=sqrt(1-b);
d=1/c;
k=k*d;
}
s=0;
for(i=1;i<n;i++) // compute rotations and sin and cos values
{
if(s>theta)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
f=atanh(e);
g=sigma*f;
s=s+g; //rotation
h=sigma*e;
l=*sinh * h;
appx=*cosh+l;
m=*cosh * h;
appy=m+*sinh;
*cosh=appx;
*sinh=appy;
}
*sinh=*sinh*k;
*cosh=*cosh*k;
}
Ora valutiamo entrambe le funzioni per alcuni valori di θ per i quali sappiamo che la funzionecorretta (quella con la ripetizioni dei passi) converge. Usiamo il seguente main.
// compile as gcc -I./ main.c -lm -o ex3
#include <cordic.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//check convergent values
double theta;
double cordic_sinh,cordic_cosh;
double cordic_sinh_no,cordic_cosh_no;
for(theta=-2.15;theta<2.16;theta=theta+0.01)
9
{
cordic_rh(theta, &cordic_sinh, &cordic_cosh);
cordic_rh_NO(theta, &cordic_sinh_no, &cordic_cosh_no);
printf("theta %.5lf\n",theta);
printf("sinh\n");
printf("cordic %.25lf\n",cordic_sinh);
printf("cordic no %.25lf\n",cordic_sinh_no);
printf("sinh() %.25lf\n",sinh(theta));
printf("cosh\n");
printf("cordic %.25lf\n",cordic_cosh);
printf("cordic no %.25lf\n",cordic_cosh_no);
printf("cosh() %.25lf\n",cosh(theta));
printf("\n");
}
return 0;
}
Segue un pezzo di output rilevante.
...
...
theta -1.86000
sinh
cordic -3.1340320705305781956440114
cordic no -1.2626472333732827735275350
sinh() -3.1340320705305781956440114
cosh
cordic 3.2897047008985738081321415
cordic no 1.6106762666486416080147137
cosh() 3.2897047008985751403997710
theta -1.85000
sinh
cordic -3.1012911781441094838385197
cordic no -1.2626472333732827735275350
sinh() -3.1012911781441117042845690
cosh
cordic 3.2585283444577402001129940
cordic no 1.6106762666486416080147137
cosh() 3.2585283444577388678453644
theta -1.84000
sinh
cordic -3.0688604174598781426652749
cordic no -1.2626472333732827735275350
sinh() -3.0688604174598776985760651
cosh
cordic 3.2276778435668020961202274
cordic no 1.6106762666486416080147137
cosh() 3.2276778435667980993173387
...
...
10
theta 1.61000
sinh
cordic 2.4014618068792210614503801
cordic no 1.2626472333732827735275350
sinh() 2.4014618068792206173611703
cosh
cordic 2.6013494209543668311823694
cordic no 1.6106762666486416080147137
cosh() 2.6013494209543654989147399
theta 1.62000
sinh
cordic 2.4275958087401279250627795
cordic no 1.2626472333732827735275350
sinh() 2.4275958087401257046167302
cosh
cordic 2.6254945078237432731782519
cordic no 1.6106762666486416080147137
cosh() 2.6254945078237401645537830
theta 1.63000
sinh
cordic 2.4539725722049094969179350
cordic no 1.2626472333732827735275350
sinh() 2.4539725722049077205610956
cosh
cordic 2.6499021463318168656542184
cordic no 1.6106762666486416080147137
cosh() 2.6499021463318164215650086
...
...
Possiamo notare che la funzione senza la ripetizione di tutte le iterazioni produce dei risultati sba-gliati. Ecco quindi una piccola dimostrazione pratica della necessità di ripetizione di alcuni passi(nel nostro caso tutti) per approssimare correttamente l’algoritmo.
Con la modalità VECTOR è possibile calcolare le funzioni inverse di seno e coseno (arcsin e arccos)e le rispettive funzioni inverse iperboliche (arcsinh e arccosh). L’idea che sta alla base della modalitàVECTOR è la seguente: si ruota nel piano il vettore (1, 0) affinchè la sua componente y nel caso diarcoseno (o x nel caso di arcocoseno) è uguale a una costante c data in input. L’angolo necessarioper allineare la componente considerata alla costante c sarà il valore dell’arcoseno o dell’arcocoseno(a seconda della componente considerata). Quindi abbiamo che c = An · θ, dove An è il guadagnodell’algoritmo di CORDIC che dipende dal numero di iterazioni dello stesso e θ è l’angolo di cuivogliamo conoscere l’arcoseno e/o arcocoseno.
Segue il codice C della funzione che permette di calcolare l’arcoseno di un certo angolo utilizzandoil metodo CORDIC nella modalità VECTOR.
void cordic_arcsin(double w, double *arcsin)
{
// compute arcsin value by vector method
// of an angle >= -0.98... <= 0.98... (in radian)
double x,y,s,e,f,g,h,l,m,appx,appy,sigma;
11
int i,n;
x=1;
y=0;
n=54;
s=0;
for(i=0;i<n;i++)
{
if(y>=w)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
f=atan(e);
g=sigma*f;
s=s+g;
h=sigma*e;
l=y * h;
appx=x-l;
m=x * h;
appy=m+y;
x=appx;
y=appy;
}
*arcsin=s;
}
Per vedere qual’è il range di valori dell’angolo θ entro il quale tale funzione converge ai reali valoridell’arcoseno utilizziamo il seguente main.
// compile as gcc -I./ main.c -lm -o ex3
#include <cordic.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//check convergent values
double theta,an;
double cordic_asin;
compute_an(&an,54);
for(theta=-1;theta<1.01;theta=theta+0.01)
{
cordic_arcsin(theta*an, &cordic_asin);
printf("theta %.5lf\n",theta);
12
printf("cordic %.25lf\n",cordic_asin);
printf("asin() %.25lf\n",asin(theta));
printf("\n");
}
return 0;
}
La funzione compute_an calcola il guadagno dell’algoritmo in base al numero di passi dello stesso.Segue il suo codice C.
void compute_an(double *an,int n)
{
double a,b,c;
int i;
*an=1;
for(i=0;i<n;i++)
{
a=(double)-2*i;
b=pow(2,a);
c=sqrt(1+b);
*an=*an*c;
}
}
Usando il main sopra riportato andiamo a confrontare i valori risultanti dalla funzione CORDICcon quelli della funzione trigonometrica arcoseno per un particolare range di valori di θ. Segue unpezzo di output rilevante.
...
...
theta -1.00000
cordic -1.7432866204723400649356790
asin() -1.5707963267948965579989817
theta -0.99000
cordic -1.4934722396714201764211793
asin() -1.4292568534704692684300653
theta -0.98000
cordic -1.3704614844717748489699716
asin() -1.3704614844717768473714159
theta -0.97000
cordic -1.3252308092796041272265484
asin() -1.3252308092796045713157582
...
...
theta 0.96000
13
cordic 1.2870022175865725166943321
asin() 1.2870022175865738489619616
theta 0.97000
cordic 1.3252308092796094562970666
asin() 1.3252308092796103444754863
theta 0.98000
cordic 1.3704614844717810662189095
asin() 1.3704614844717841748433784
theta 0.99000
cordic 1.4934722396714201764211793
asin() 1.4292568534704794824818919
...
...
Possiamo notare che la funzione CORDIC in esame converge con −0.98 . . . ≤ θ(radianti) ≤ 0.98 . . .ossia −56.14◦ . . . ≤ θ(gradi) ≤ 56.14◦ . . .. Oltre questo range non abbiamo una buona approssima-zione.
Segue il codice C della funzione che permette di calcolare l’arcocoseno di un certo angolo utilizzandoil metodo CORDIC nella modalità VECTOR.
void cordic_arcos(double w, double *arcos)
{
// compute arcos value by vector method
// of an angle >= -0.17... <= 0.6... (in radian)
double x,y,s,e,f,g,h,l,m,appx,appy,sigma;
int i,n;
x=1;
y=0;
n=54;
s=0;
for(i=0;i<n;i++)
{
if(x>=w)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
f=atan(e);
g=sigma*f;
s=s-g;
h=sigma*e;
l=y * h;
appx=x-l;
14
m=x * h;
appy=m+y;
x=appx;
y=appy;
}
*arcos=s;
}
Per vedere qual’è il range di valori dell’angolo θ entro il quale tale funzione converge ai reali valoridell’arcocoseno utilizziamo il seguente main.
// compile as gcc -I./ main.c -lm -o ex3
#include <cordic.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//check convergent values
double theta,an;
double cordic_acos;
compute_an(&an,54);
for(theta=-0.2;theta<0.65;theta=theta+0.01)
{
cordic_arcos(theta*an, &cordic_acos);
printf("theta %.5lf\n",theta);
printf("cordic %.25lf\n",cordic_acos);
printf("acos() %.25lf\n",acos(theta));
printf("\n");
}
return 0;
}
In questo modo andiamo a confrontare i valori risultanti dalla funzione CORDIC con quelli dellafunzione trigonometrica arcocoseno per un particolare range di valori di θ. Segue un pezzo di outputrilevante.
...
...
theta -0.19000
cordic 1.7432866204723400649356790
acos() 1.7619584733259563424923044
theta -0.18000
cordic 1.7432866204723400649356790
acos() 1.7517827780414443328282914
15
theta -0.17000
cordic 1.7416259959240010246617203
acos() 1.7416259959240010246617203
theta -0.16000
cordic 1.7314869797468075418578337
acos() 1.7314869797468070977686239
theta -0.15000
cordic 1.7213645995715829428718280
acos() 1.7213645995715824987826181
...
...
theta 0.58000
cordic 0.9520676361226447781405113
acos() 0.9520676361226450001851163
theta 0.59000
cordic 0.9397374860168745680510938
acos() 0.9397374860168747900956987
theta 0.60000
cordic 0.9272952180016114098748403
acos() 0.9272952180016117429417477
theta 0.61000
cordic -1.7432866204723400649356790
acos() 0.9147357358699733653750741
theta 0.62000
cordic -1.7432866204723400649356790
acos() 0.9020536235925242785071987
...
...
Possiamo notare che la funzione CORDIC in esame converge con −0.17 . . . ≤ θ(radianti) ≤ 0.6 . . .ossia −9.74◦ . . . ≤ θ(gradi) ≤ 34.37◦ . . .. Oltre questo range non abbiamo una buona approssima-zione.
Segue il codice C della funzione che permette di calcolare l’arcoseno iperbolico di un certo an-golo utilizzando il metodo CORDIC nella modalità VECTOR.
void cordic_arcsinh(double w, double *arcsinh)
{
// compute arcsinh value by vector method
// of an angle >= -1.26... <= 1.26... (in radian)
double x,y,s,e,f,g,h,l,m,appx,appy,sigma;
int i,n;
16
x=1;
y=0;
n=54;
s=0;
for(i=1;i<n;i++)
{
if(y>=w)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
f=atanh(e);
g=sigma*f;
s=s+g;
h=sigma*e;
l=y * h;
appx=x+l;
m=x * h;
appy=m+y;
x=appx;
y=appy;
}
*arcsinh=s;
}
Per vedere qual’è il range di valori dell’angolo θ entro il quale tale funzione converge ai reali valoridell’arcoseno iperbolico utilizziamo il seguente main.
// compile as gcc -I./ main.c -lm -o ex3
#include <cordic.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//check convergent values
double theta,anh;
double cordic_asinh;
compute_anh(&anh,54);
for(theta=-1.28;theta<1.29;theta=theta+0.01)
{
cordic_arcsinh(theta*anh, &cordic_asinh);
printf("theta %.5lf\n",theta);
printf("cordic %.25lf\n",cordic_asinh);
printf("asinh() %.25lf\n",asinh(theta));
17
printf("\n");
}
return 0;
}
La funzione compute_anh calcola il guadagno dell’algoritmo in base al numero di passi dellostesso. Segue il suo codice C.
void compute_anh(double *anh,int n)
{
double a,b,c;
int i;
*anh=1;
for(i=1;i<n;i++)
{
a=(double)-2*i;
b=pow(2,a);
c=sqrt(1-b);
*anh=*anh*c;
}
}
Usando il main sopra riportato andiamo a confrontare i valori risultanti dalla funzione CORDICcon quelli della funzione trigonometrica arcoseno iperbolico per un particolare range di valori di θ.Segue un pezzo di output rilevante.
...
...
theta -1.28000
cordic -1.0554693737354847726805929
asinh() -1.0661976449070125205764725
theta -1.27000
cordic -1.0554693737354847726805929
asinh() -1.0600262371581044007484707
theta -1.26000
cordic -1.0538247603460848544898454
asinh() -1.0538247603460844104006355
theta -1.25000
cordic -1.0475930126492589700148983
asinh() -1.0475930126492587479702934
theta -1.24000
cordic -1.0413307920087899738348369
asinh() -1.0413307920087899738348369
...
...
18
theta 1.24000
cordic 1.0413307920087913061024665
asinh() 1.0413307920087910840578616
theta 1.25000
cordic 1.0475930126492598581933180
asinh() 1.0475930126492598581933180
theta 1.26000
cordic 1.0538247603460857426682651
asinh() 1.0538247603460857426682651
theta 1.27000
cordic 1.0554693737354847726805929
asinh() 1.0600262371581055109714953
theta 1.28000
cordic 1.0554693737354847726805929
asinh() 1.0661976449070136307994972
...
...
Possiamo notare che la funzione CORDIC in esame converge con −1.26 . . . ≤ θ(radianti) ≤ 1.26 . . .ossia −72.19◦ . . . ≤ θ(gradi) ≤ 72.19◦ . . .. Oltre questo range non abbiamo una buona approssima-zione.
Segue il codice C della funzione che permette di calcolare l’arcocoseno iperbolico di un certo angoloutilizzando il metodo CORDIC nella modalità VECTOR.
void cordic_arcosh(double w, double *arcosh)
{
// compute arcosh value by vector method
// of an angle >= 1.21... <= 1.61... (in radian)
double x,y,s,e,f,g,h,l,m,appx,appy,sigma;
int i,n;
x=1;
y=0;
n=54;
s=0;
for(i=1;i<n;i++)
{
if(x>=w)
sigma=-1;
else
sigma=1;
e=pow(2,(double)-i);
f=atanh(e);
g=sigma*f;
19
s=s+g;
h=sigma*e;
l=y * h;
appx=x+l;
m=x * h;
appy=m+y;
x=appx;
y=appy;
}
*arcosh=s;
}
Per vedere qual’è il range di valori dell’angolo θ entro il quale tale funzione converge ai reali valoridell’arcocoseno iperbolico utilizziamo il seguente main.
// compile as gcc -I./ main.c -lm -o ex3
#include <cordic.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//check convergent values
double theta,anh;
double cordic_acosh;
compute_anh(&anh,54);
for(theta=1.01;theta<1.65;theta=theta+0.01)
{
cordic_arcosh(theta*anh, &cordic_acosh);
printf("theta %.5lf\n",theta);
printf("cordic %.25lf\n",cordic_acosh);
printf("acosh() %.25lf\n",acosh(theta));
printf("\n");
}
return 0;
}
In questo modo andiamo a confrontare i valori risultanti dalla funzione CORDIC con quelli dellafunzione trigonometrica arcocoseno iperbolico per un particolare range di valori di θ. Segue unpezzo di output rilevante.
...
...
theta 1.18000
cordic -1.0554693737354847726805929
acosh() 0.5913460951268451060158782
20
theta 1.19000
cordic -1.0554693737354847726805929
acosh() 0.6070761632470630386748667
theta 1.20000
cordic -1.0554693737354847726805929
acosh() 0.6223625037147789695879396
theta 1.21000
cordic 0.6372373797541088791263064
acosh() 0.6372373797541083240147941
theta 1.22000
cordic 0.6517292837263393145974533
acosh() 0.6517292837263388705082434
theta 1.23000
cordic 0.6658635291565559999327206
acosh() 0.6658635291565551117543009
...
...
theta 1.59000
cordic 1.0389201097727607248089043
acosh() 1.0389201097727607248089043
theta 1.60000
cordic 1.0469679150031896419648092
acosh() 1.0469679150031887537863895
theta 1.61000
cordic 1.0549335963808532667940199
acosh() 1.0549335963808523786156002
theta 1.62000
cordic 1.0554693737354847726805929
acosh() 1.0628191274087777085100015
theta 1.63000
cordic 1.0554693737354847726805929
acosh() 1.0706264039066135662636725
...
...
Possiamo notare che la funzione CORDIC in esame converge con 1.21 . . . ≤ θ(radianti) ≤ 1.61 . . . os-sia 69.32◦ . . . ≤ θ(gradi) ≤ 92.24◦ . . .. Oltre questo range non abbiamo una buona approssimazione.
Concludiamo questa relazione affermando che le nostre calcolatrici scientifiche grafiche (modelloEL-9300 della sharp) non fanno uso del metodo del CORDIC per il calcolo delle funzioni trigono-metriche (o per lo meno non come lo abbiamo implementato ed analizzato noi in questa relazione).Per esempio con le nostre calcolatrici siamo in grado di valutare il seno di 2 radianti, cosa che nonè possibile con il CORDIC in modalità ROTATION. Ci rimane ancora da scoprire come effettiva-mente vengono calcolate le funzioni trigonometriche nelle nostre calcolatrici, ma questa è un’altra
21
storia.
22