ForTran: istruzione IF e funzione COS(X)

maximilianprivrat
Buongiorno a tutti,

stavo facendo un esercizio per il linguaggio di programmazione in Fortran mi sono venuti dei dubbi. Il quesito era:
La distanza orizzontale (d) percorsa da una pallina lanciata in aria con velocità iniziale v0 ed angolo iniziale rispetto al suolo e data dall'equazione:

$ d = -2 (v^2)/g cos(vartheta )sin(vartheta ) $

Calcolare tale distanza per v0 = 20 m/s e per tutti gli angoli compresi fra 0 e 90 gradi, per incrementi progressivi di 1°. Determinare poi l'angolo corrispondente alla distanza massima. Si assume che non vi sia attrito da parte dell'aria; g = 9,81 m/s'2.

ho scritto il programma compilato con PLATO su un COREI3:

! file pallina.f90

!trovare l'angolo di gittata massima dmax di una pallina lanciata a 20 m/s

PROGRAM pallina


IMPLICIT NONE
REAL :: d, dmax, angolo
REAL , PARAMETER :: pigreco=3.14159265 ,g=-9.81, v0= 20 ! m/s
INTEGER :: i

! sezione esecutiva

dmax=0

DO i=0, 90 ! da 0° a 90°

angolo=real(i)*2*pigreco/360 ! trasforma i gradi in radianti

d=(-2*(v0**2)/g)*(cos(angolo))*(sin(angolo))

IF (d>dmax) dmax=d


WRITE (*,*) 'ANGOLO IN GRADI ',i,' angolo in radianti ',angolo,' DISTANZA DEL LANCIO', d
END DO

WRITE (*,*) 'LA DISTANZA MAX E''',d,' metri CON UN ANGOLO DI LANCIO IN gradi DI ',i

end program pallina

L'output va bene fino all'ulimo valore dove il calcolo del coseno mi da un valore negativo. Il che rende anche d negativo.
Il primo problema di questo programma è che non so come ottenere il risultato corretto cioè d=0 a 90°.
Il secondo problema è che IF alla fine mi pone dmax corrispondente a quello dei 90° cioè 3.5e-06

Qualcuno sa come risolvere queste incongruenze

Grazie mille!

Risposte
apatriarca
Per prima cosa non è l'IF ad essere sbagliato, ma il testo finale in cui fornisci il risultato. Stai infatti stampando d (non dmax..) e i che saranno necessariamente uguali all'ultimo valore calcolato nel ciclo. Devi introdurre una nuova variabile, per esempio imax, per contenere il valore massimo dell'angolo.

L'altro errore è invece semplicemente dovuto a problemi di precisione. Siccome il valore di \(\pi\) è solo approssimato, lo sarà anche quello di angolo. Inoltre c'è necessariamente anche una approssimazione nel calcolo del coseno e seno per cui il risultato sarà sbagliato. Infine stai usando valori in singola precisione per cui l'errore sarà ulteriormente maggiore. La soluzione migliore a questo problema è quella di calcolare i valori solo tra 1° e 89° lasciando perdere i due valori in cui il risultato deve essere zero.

Quella che segue è la mia versione modificata del tuo codice (testata con gfortran).
! file pallina.f90
! trovare l'angolo di gittata massima dmax di una pallina lanciata a 20 m/s

PROGRAM pallina

IMPLICIT NONE
REAL*8 :: d, dmax, angolo
REAL*8 , PARAMETER :: pigreco=3.14159265 ,g=-9.81, v0= 20 ! m/s
INTEGER :: i, imax

! sezione esecutiva

dmax=0
imax=0

DO i=1, 89 ! da 1° a 89°

angolo = real(i)*2*pigreco/360 ! trasforma i gradi in radianti

d=(-2*(v0**2)/g)*(cos(angolo))*(sin(angolo))

IF (d>dmax) THEN
    dmax=d
    imax=i
END IF


WRITE (*,*) 'ANGOLO IN GRADI ',i,' angolo in radianti ',angolo,' DISTANZA DEL LANCIO', d
END DO

WRITE (*,*) 'LA DISTANZA MAX E''',dmax,' metri CON UN ANGOLO DI LANCIO IN gradi DI ',imax

end program pallina

apatriarca
Volendo fare altre considerazioni (che però il compilatore potrebbe in parte già fare per conto suo):
1. \( \sin 2\alpha = 2\,\sin\alpha\,\cos\alpha \)
2. Solo il calcolo del coseno e seno dipendono dall'angolo per cui il resto può essere estratto dal ciclo.

maximilianprivrat
Grazie mille! :-) adesso ho capito!
rimane un problema sul KIND delle variabili, se lancio il programmino qui di seguito:

PROGRAM test_select_real
IMPLICIT NONE
INTEGER :: n1, n2, n3, n4, n5, n6, n7
n1 = SELECTED_REAL_KIND(p=6,r=37)
n2 = SELECTED_REAL_KIND(r=100)
n3 = SELECTED_REAL_KIND(p=13,r=200)
n4 = SELECTED_REAL_KIND(p=13)
n5 = SELECTED_REAL_KIND(17)
n6 = SELECTED_REAL_KIND(p=11,r=500)
n7 = SELECTED_REAL_KIND(17,500)
PRINT*, n1,n2,n3,n4,n5,n6,n7
END PROGRAM

ottengo il seguente output:
1,2,2,2,3,3,3

Quindi dovrei usare KIND(3) ?

apatriarca
Suppongo di sì.

maximilianprivrat
ok grazie mille!

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.