lunedì 12 settembre 2011

I logaritmi come li fanno i computer — parte 4

Il programma dell'altra volta per calcolare seno e coseno funzionava bene, ma aveva il problema di utilizzare, ad ogni ciclo, quattro moltiplicazioni. Per un sistema dotato di poche risorse, le moltiplicazioni sono Cose Brutte.

Ma si può fare di meglio.

Riprendiamo le formule di somma e sottrazione per seno e coseno:

cos(x±y) = cos(x)cos(y)∓sin(x)sin(y),
sin(x±y) = sin(x)cos(y)±cos(x)sin(y),

e modifichiamole un po'. Se raccogliamo cos(y) in entrambe, otteniamo queste:

cos(x±y) = cos(y)[cos(x)∓sin(x)tan(y)],
sin(x±y) = cos(y)[sin(x)±cos(x)tan(y)].

Ma le tangenti che compaiono sono le tangenti degli angoli che compongono il ventaglio, e quindi sono i numeri 1, 1/2, 1/4, 1/8, 1/16, e così via. Ora, se proviamo a calcolare i primi termini delle successioni di seni e coseni, otteniamo una relazione interessante. Per farlo, indichiamo con A0, A1, … gli angoli che formano i vari settori del ventaglio. Indichiamo invece con T0, T1, … le approssimazioni che otteniamo col ventaglio fermandoci al settore numero 1, 2, eccetera. Insomma, nel nostro caso, calcolo di seno e coseno dell'angolo di 70 gradi, abbiamo che T0 = 0, T1 = A0, T2 = A0+A1, T3 = A0+A1-A2, e così via.

Allora i nostri calcoli diventano:

cos(T1) = cos(A0),
sin(T1) = cos(A0).

cos(T2) = cos(A1)[cos(T1)-1/2sin(T1)] = cos(A1)cos(A0)[1/2],
sin(T2) = cos(A1)[sin(T1)+1/2cos(T1)] = cos(A1)cos(A0)[3/2].

cos(T3) = cos(A2)[cos(T2)+1/4sin(T1)] = cos(A2)cos(A1)cos(A0)[7/8],
sin(T3) = cos(A2)[sin(T2)-1/4cos(T1)] = cos(A2)cos(A1)cos(A0)[11/8].

A parte i numeri tra parentesi quadre, riconosciamo una formula generale. Dopo aver usato l'ultimo settore del ventaglio avremo:


cos(T24) = cos(A23)cos(A22)…cos(A0)[C24],
sin(T24) = cos(A23)cos(A22)…cos(A0)[S24].

Lo so che ci sono ancora dei prodotti, ma ne parliamo dopo, per ora concentriamoci sui numeri tra parentesi quadre, che si possono calcolare in modo ricorsivo così:

C= 1,
S= 0,
Cm+1 = Cm-DmSm/2m,
Sm+1 = Sm+DmCm/2m,

dove Dm vale +1 oppure -1 a seconda del segno con cui Am compare nel calcolo dell'angolo col metodo del ventaglio.

Abbiamo allora migliorato l'algoritmo, anche se non abbiamo eliminato completamente i prodotti. Ne abbiamo diminuito il numero, comunque, e abbiamo introdotto una divisione per una potenza di 2 che è molto economica da fare per un computer, basta fare uno shift verso destra.

Ecco un programmino che esegue questi calcoli:

# costruisce le tabelle

from math import atan,sin,cos,pi

ango={}
seni={}
cosi={}

for i in xrange(24):
 ango[i]=atan(1./2**i)
 cosi[i]=cos(ango[i])


def seno2(x):
 
 s=0
 c0=1
 s0=0
 d=1.
 ct0=1
 st0=0
 
 
 for i in xrange(24):
  
  if s>x:
   s-=ango[i]
   c1=c0+d*s0
   s1=s0-d*c0
  else: 
   s+=ango[i]
   c1=c0-d*s0
   s1=s0+d*c0

  c0=c1
  s0=s1
  d/=2

  ct1=ct0*cosi[i]
  ct0=ct1

 return ct0*s1


v1 = seno2(70./180*pi)
v2 = sin(70./180*pi)

print v1,v2,abs(v1-v2)

Ed ecco l'output:

.939692638163 0.939692620786 1.73768645029e-08

Ora si tratta di eliminare completamente tutti i prodotti. Per riuscirci, bisogna girare il ventaglio.

Nessun commento: