A Fortran programozásban a tömbök gyakran használt adatszerkezetek, amelyek segítségével hatékonyan kezelhetjük az ismétlődő adatokat. Az alábbi program egy egyszerű példát mutat arra, hogyan találhatjuk meg egy tömbben a legnagyobb és legkisebb értéket, és hogyan használhatjuk az implicit DO ciklusokat adatkezelés során.

A programban először egy tömböt definiálunk, amely 10 elemnyi számot tartalmaz. A cél az, hogy megtaláljuk a legnagyobb és legkisebb számot, valamint azok pozícióit a tömbben. A kezdő értékként a legnagyobb és legkisebb számot a tömb első eleméből vesszük, és egy ciklus segítségével összehasonlítjuk az aktuális elemet a már tárolt legnagyobb és legkisebb értékekkel.

A program működése a következő:

mathematica
write(*,*) (M(I),I=1,10)
BIG = M(1) ! Kezdetben feltételezzük, hogy az első adat a legnagyobb és legkisebb érték
PB = 1 ! A legnagyobb érték pozíciója
SMALL = M(1)
PS = 1 ! A legkisebb érték pozíciója
DO I = 2, 10
IF (BIG .LT. M(I)) THEN
BIG = M(I)
PB = I ! A pozíció változik ENDIF IF (SMALL .GT. M(I)) THEN
SMALL = M(I)
PS = I ! A pozíció változik ENDIF END DO WRITE(*,*) 'A LEGNAGYOBB ÉRTÉK: ', BIG, " A pozíciója: ", PB
WRITE(*,*) 'A LEGKISEBB ÉRTÉK: ', SMALL, " A pozíciója: ", PS
STOP

Ez a program először kiírja a tömb összes számát, majd meghatározza a legnagyobb és legkisebb értéket, valamint azok pozícióit. A kimeneti eredmény az alábbiakban látható:

less
A LEGNAGYOBB ÉRTÉK: 92 A pozíciója: 7
A LEGKISEBB ÉRTÉK: 12 A pozíciója: 1

A programban az "implied DO" ciklus egy különleges ciklusformátum, amely lehetővé teszi, hogy egyszerűbben olvassunk és írjunk adatokat a tömbből. Például, a következő kódrészletben:

mathematica
WRITE(*,*) (M(I),I=1,10)

Ez a kód egyszerűsíti a ciklust, mivel nem szükséges külön DO ciklust írni minden egyes elemhez. Az összes adat egy sorban, szünet nélkül kerül kiírásra.

Ha két dimenziós tömbökkel dolgozunk, akkor az implied DO ciklusok formája az alábbiak szerint néz ki:

mathematica
READ(*,*) ((A(I,J),J=1,n),I=1,m)
WRITE(*,*) ((A(I,J),J=1,n),I=1,m)

Ebben az esetben az "I" ciklus az egyes sorokat, míg a "J" ciklus az oszlopokat iterálja át. Az "I" változó minden egyes lépésnél az egyes sorokat változtatja, míg a "J" változó az adott sor oszlopait. Ez a megoldás lehetővé teszi, hogy könnyen beolvassunk és kiírjunk kétdimenziós adatokat.

Ha három dimenziós tömbökkel dolgozunk, az implied DO ciklusok hasonlóan alkalmazhatóak. A három dimenzió kezelése így történhet:

mathematica
READ(*,*) ((A(I,J,K),K=1,p),J=1,n),I=1,m
WRITE(*,*) ((A(I,J,K),K=1,p),J=1,n),I=1,m

Az implicit DO ciklusok nemcsak a beolvasásnál és a kiírásnál használhatók, hanem a program egyéb részein is. Például, egy "data" állításban is alkalmazhatók:

kotlin
data (x(i),i=1,8)/1, 2, 3, 4, 5, 6, 7, 8/
data (y(i),i=1,8)/2, 4, 5, 8, 12, 15, 17, 20/

Ezáltal könnyen inicializálhatunk tömböket anélkül, hogy minden egyes értéket külön-külön meg kellene adni.

A gyakorlati alkalmazások során előfordulhat, hogy egy adott adat előfordulási gyakoriságát szeretnénk meghatározni. Ehhez létrehozhatunk egy olyan programot, amely minden egyes számhoz tartozó gyakoriságot számol. A program az alábbiak szerint néz ki:

pgsql
integer nf(100) write(*,*) 'Adja meg a számadatokat' Read(*,*) nd write(*,*) 'Adja meg az adatok minimum és maximum értékét' read(*,*) mind,maxd do i=mind,maxd nf(i) = 0 ! Minden szám előfordulási gyakoriságát nullázza enddo do i=1,nd nf(nv(i)) = nf(nv(i)) + 1 ! Növeli az adott szám előfordulásának gyakoriságát enddo write(*,*) 'Szám Előfordulás' do i=mind,maxd
if (nf(i).ne.0) write(*,*) i,' ', nf(i)
enddo

Ez a program képes kiszámolni az előfordulások számát, majd kiírja azokat. Ha az egyes számok nem fordulnak elő, akkor azokat nem írja ki.

Amennyiben a program célja, hogy automatikusan találja meg az adatok minimum és maximum értékeit, ezt a logikát a következő módon alkalmazhatjuk:

mathematica
mind = nv(1)
maxd = nv(1)
DO I=2, nd
IF (maxd.LT.nv(I)) maxd = nv(I)
IF (mind.GT.nv(I)) mind = nv(I) END DO

Ezáltal a program nemcsak a beírt adatokat kezeli, hanem automatikusan képes meghatározni azok szélsőértékeit, így rugalmasságot biztosít nagyobb adathalmazok esetén.

Hogyan történik a rendezés különböző adattípusok esetén a Fortran programozásban?

A Fortran programozásban a rendezési algoritmusok, mint a buborékrendezés, gyakran használatosak különböző típusú adatok, például egész számok, valós számok és karakterláncok rendezésére. Az egyik legismertebb és legelterjedtebb algoritmus ezen a téren a buborékrendezés, amely egyszerű, de hatékony megoldást kínál arra, hogy növekvő vagy csökkenő sorrendbe rendezzünk egy adatsort.

A buborékrendezés alapelve az, hogy az algoritmus sorban összehasonlítja az elemeket, és ha szükséges, kicseréli őket. A következő lépésekkel magyarázható: elindítunk két ciklust, egyet az adatsor elejétől a végéig, a másikat pedig az aktuális elem után az összes többi elemig. Minden iteráció után a legnagyobb vagy legkisebb elem „buborékol” a sor végére. A rendezés végén a legnagyobb vagy legkisebb elem kerül az utolsó pozícióba, majd a folyamat folytatódik a következő elemeken.

A kód megírása egyszerű: az adatokat a memóriában tároljuk, majd egy ideiglenes változó segítségével cseréljük ki őket. A Fortran nyelvben egy-egy ilyen műveletet így valósíthatunk meg:

fortran
T = A(I) A(I) = A(J) A(J) = T

Ez a kis részlet a programban azt mutatja, hogyan történik két elem cseréje a rendezési folyamat során. Az alapvető logika egyszerűen csak a két adatérték összehasonlításából és szükség esetén cseréjéből áll. A program képes kezelni nemcsak egész számokat, hanem valós számokat is, ahogy az a példában is látszik.

A rendezési algoritmusok alkalmazása nem csak numerikus típusokra korlátozódik. A karakterláncok rendezésére is alkalmazhatók hasonló módszerek. Mivel a karaktereket az ASCII kódok szerint tárolja a számítógép, a karakterláncok összehasonlítása és rendezése a numerikus adatokat kezelő logikával történhet. Mivel az ASCII kódok értékei az angol ábécé betűire vonatkozóan növekvő sorrendben vannak, a karakterek összehasonlítása és cseréje ugyanúgy végezhető, mint a számok esetében.

A karakterláncok rendezése például így valósítható meg Fortranban:

fortran
T = A(I) A(I) = A(J) A(J) = T

Ez ugyanúgy végbemegy, mint a számok esetében, csak itt karakterek cserélődnek helyet. A stringek kezelésében azonban egy plusz megjegyzést kell tenni: mivel az ASCII kódok nemcsak betűket, hanem számokat és szimbólumokat is tartalmaznak, előfordulhat, hogy az adott string tartalmának helyes rendezése érdekében a formátumokat is figyelembe kell venni. Ha például egy nevet és egy címet, például "Dr. Kovács" és "Mészáros" stringeket szeretnénk rendezni, fontos, hogy mindkét elem tartalmazza a megfelelő karaktereket és szóközöket.

A fenti példák alapján jól látszik, hogy a Fortran rendkívül rugalmas eszközként működik különböző adattípusok rendezésére. Ha a felhasználó bonyolultabb adatstruktúrákat szeretne rendezni, például mátrixokat, akkor is alkalmazható a buborékrendezés módszere. A mátrixok rendezése lehetőséget ad arra, hogy a felhasználó az egyes elemeket az általuk választott sorrendben kezelje, sőt a mátrixok szorzásának eredményeit is ki tudja nyomtatni.

A programozás során gyakran előfordul, hogy nem egyetlen adatbázist vagy tömböt kell rendezni, hanem többet. Ilyen esetekben különböző eljárások és alprogramok használatával könnyen megoldható, hogy az adatok rendezése ne egyesével, hanem csoportosan történjen. A Fortran lehetőséget biztosít arra is, hogy az alprogramok és alfüggvények használatával a felhasználó hatékonyan dolgozzon több adatkészlettel egyszerre, miközben mindegyiket önállóan kezelheti.

Az alábbi programkódban bemutatjuk, hogyan történik két adatbázis, például két különböző adatállomány rendezése egyszerre:

fortran
WRITE(*,*) 'Input data number in data set 1'
READ(*,*) N WRITE(*,*) 'Input data of data set 1' READ(*,*) (A(I),I=1,N) CALL SORTDATA(N,A) WRITE(*,*) 'Sorted data set 1 (ascending order)' WRITE(*,*) (A(I),I=1,N) WRITE(*,*) 'Sorted data set 1 (descending order)' WRITE(*,*) (A(I),I=N,1,-1)

Ebben a példában az első adatkészletet az A(I) tömbben tároljuk, majd a SORTDATA alprogram hívásával történik az adatok rendezése. Az adatokat először növekvő sorrendben, majd csökkenő sorrendben rendezzük. Ez a megoldás lehetőséget ad arra, hogy különböző adatállományokat rendezzünk ugyanazzal az algoritmussal.

A program képes különböző típusú adatokat kezelni, beleértve a negatív számokat is. Az alábbi kimenet például azt mutatja, hogyan működik a program, amikor az adatokat negatív számokkal és azonos értékekkel látjuk el:

fortran
Sorted data set 2 (ascending order)
-3. 1. 5. 6. 12. 12. 78. Sorted data set 2 (descending order) 78. 12. 12. 6. 5. 1. -3.

Egy másik érdekes felhasználási lehetőség a karakterláncok rendezése. Amikor a programot stringekkel futtatjuk, az ASCII kódok szerint történik a rendezés, például egy névsort a következőképpen lehet rendezni:

fortran
Sorted data set 1 (alphabetical order) PRABAL PRITAM TANUJA TRINA TRISHYA

A Fortran programozás tehát nemcsak a numerikus típusok, hanem a karakteradatok és komplex adatstruktúrák rendezésére is kiválóan alkalmas.

Hogyan találjuk meg egy n-ed fokú polinom összes valós gyökerét?

A valós fizikai problémák többségében előforduló jelenség, hogy egy polinomegyenlet gyökeit kell megtalálnunk, legyenek azok valósak vagy komplexek. Az alábbiakban ismertetett módszertan azokra az esetekre érvényes, amikor a polinom minden gyöke valós. A cél a gyökök kiszámítása lépésről lépésre, olyan algoritmus segítségével, amely a numerikus stabilitás mellett biztosítja a pontosságot is.

A kiindulási pontunk egy általános n-ed fokú polinom:

f(x) = aₙxⁿ + aₙ₋₁xⁿ⁻¹ + aₙ₋₂xⁿ⁻² + ... + a₂x² + a₁x + a₀

A polinom kiértékelésére a Horner-módszer alkalmazható, amely lényegesen leegyszerűsíti a számításokat:

f(x) = (...((aₙx + aₙ₋₁)x + aₙ₋₂)x + ... + a₁)x + a₀

Egy közelítő kezdőértékkel, x₀-val indulva, a gyökök meghatározása Newton–Raphson-módszerrel történik, iteratív módon:

x₁ = x₀ – f(x₀)/f′(x₀)

A derivált f′(x) is szintén a Horner-eljárással hatékonyan kiszámítható:

f′(x) = n·aₙxⁿ⁻¹ + (n-1)·aₙ₋₁xⁿ⁻² + ... + 2a₂x + a₁
= (...((n·aₙx + (n-1)·aₙ₋₁)x + (n-2)·aₙ₋₂)x + ... + 2a₂)x + a₁

Amint megtalálunk egy gyököt, xr-t, a polinom felbontható:

p(x) = (x – xr)·q(x)

Itt q(x) egy (n–1)-ed fokú polinom. A q(x) együtthatói szintetikus osztással határozhatók meg, amely eljárás nem igényel tényleges osztást, hanem egy rekurzív relációt alkalmaz:

bₙ₋₁ = aₙ + xr·bₙ, ahol bₙ = 0

Ez a visszavezetés minden egyes gyök kiszámítása után újra alkalmazható, így a következő gyök már a redukált fokszámú polinomra számítható, mindaddig, amíg elsőfokú polinomhoz nem érünk, amely gyöke egyszerűen –a₀/a₁ alakban meghatározható.

A teljes folyamat automatizálható: kezdetben beolvassuk a polinom fokszámát és együtthatóit, majd egy kezdő közelítéssel elindítjuk az első gyök keresését. Miután egy gyök meghatározásra került, a szintetikus osztással előállítjuk a következő fokszámú polinomot, és az új gyök keresését az előző gyökből indítjuk. Az iterációs folyamat során a gyököket egymás után meghatározzuk, miközben az algoritmus figyeli a konvergenciát, és megáll, ha a változás a kívánt határérték alá csökken.

A gyökök meghatározása során az algoritmus pontosan nyomon követi a konvergencia menetét, így a felhasználó látja, hogyan közelít a Newton–Raphson-módszer a pontos gyökökhöz. Ez különösen fontos numerikus szempontból, hiszen bizonyos esetekben – például többszörös gyököknél – a módszer lassabban konvergálhat, és ez befolyásolhatja a gyökök pontosságát.

A szintetikus osztás, mint eszköz, kulcsfontosságú ebben az eljárásban: az újabb és újabb redukált polinomok előállítása minimális számítási ráfordítással történik, elkerülve az explicit polinomosztást. Ezzel együtt a Horner-módszer biztosítja a numerikus stabilitást és a hibák akkumulálódásának minimalizálását, különösen magasabb fokszámú polinomok esetén.

Fontos, hogy az algoritmus csak akkor működik megbízhatóan, ha a polinomnak kizárólag valós gyökei vannak. Komplex gyökök jelenléte esetén a Newton–Raphson-módszer komplex számokkal való kiterjesztése szükséges, ami teljesen más numerikus és programozási megközelítést igényel.

Az olvasónak tisztában kell lennie azzal is, hogy a kezdő közelítés megválasztása kulcsfontosságú lehet: rossz kezdeti érték esetén az iteráció nem biztos, hogy konvergál, vagy másik gyökhöz fog tartani. Tapasztalat és a polinom viselkedésének előzetes vizsgálata gyakran segít a megfelelő közelítés kiválasztásában.

A gyakorlatban a program által adott visszajelzések – a gyökök konvergenciájának lépései – lehetőséget adnak a numerikus viselkedés vizsgálatára is. Ezáltal nemcsak a gyökök értékét kapjuk meg, hanem betekintést nyerünk abba is, hogy hogyan viselkedik a megoldási folyamat különféle kiindulási értékek és polinomszerkezetek esetén.

Hogyan oldjuk meg az inverz interpolációs problémát?

Az inverz interpolációs problémák megoldása fontos része a numerikus analízisnek, különösen akkor, amikor az adott függvény értékei alapján kell meghatároznunk a függvény értékére vonatkozó bemeneti értéket. Az alábbiakban bemutatott példa segít a koncepció megértésében, amely a gyakran alkalmazott interpolációs módszerek alkalmazásával oldja meg az inverz probléma különböző típusait.

Tegyük fel, hogy négy adatpontot kaptunk, és a célunk az, hogy megtaláljuk azt az x értéket, amelyhez a függvény értéke 0,5. Az ilyen típusú feladatok megoldásához ugyanazt a programot alkalmazhatjuk, amelyet az interpolációs problémák esetén is használunk. Azonban az adatokat nem x, y párként kell megadni, hanem y, x párként kell bevinnünk őket a programba. Fontos, hogy figyelmen kívül hagyjuk azt az üzenetet, amely az x, y párokról szól, mert itt az adatok sorrendje fordított. A program futtatása során figyelni kell arra, hogy az adatokat helyesen adjuk meg, és a kimeneti eredmények is az inverz kapcsolaton alapulnak.

Például az alábbi adatokat kapjuk:

Adott adatok:
x | y
0.46 | 0.4846555
0.47 | 0.4937452
0.48 | 0.5027498
0.49 | 0.5116683

A program kimenetében a kérdéses értékek alapján a következő eredmények jelennek meg:

Adott adatpárok:
y | x
0.4846555 | 0.46
0.4937452 | 0.47
0.5027498 | 0.48
0.5116683 | 0.49

A program kimenete szerint, ha a függvény értéke 0.5, akkor az x értékének 0.476936072-nek kell lennie. Ez azt jelenti, hogy az x = 0.476936072 pontban a függvény értéke pontosan 0.5 lesz.

Ez a módszer lehetővé teszi, hogy az inverz interpolációs feladatokat hatékonyan megoldjuk, miközben minimalizáljuk az analitikai számítások szükségességét. A program nemcsak az interpolációs problémák, hanem az inverz problémák esetén is kiválóan alkalmazható.

A fentiekben bemutatott algoritmusok és módszerek alapvetően a numerikus analízis világába vezetnek, ahol fontos megérteni, hogyan alkalmazzuk őket különböző típusú matematikai feladatok megoldására. Az ilyen típusú problémák megoldásához gyakran szükség van a programozási készségekre és a matematikai módszerek alapos ismeretére. Fontos, hogy a program futtatása előtt pontosan meghatározzuk az adatokat és helyesen adjuk meg őket a program számára, különben az eredmény pontatlan lehet.

Ezen kívül a numerikus módszerek alkalmazása során, például az interpolációk esetén, mindig figyelembe kell venni a pontosságot és az iterációk számát is, hogy elérjük a kívánt eredményt. A numerikus analízis gyakran kompromisszumot jelent a számítási idő és a pontosság között, így a megfelelő módszer kiválasztása kulcsfontosságú.

Hogyan találjunk numerikus deriváltakat és oldjunk elsőrendű differenciálegyenleteket?

A numerikus differenciálás egy alapvető technika, amely lehetővé teszi számunkra, hogy egy függvény deriváltját meghatározzuk, amikor nem rendelkezünk annak analitikus kifejezésével. Ez különösen hasznos a mérési adatok elemzésénél, ahol az ismeretlen függvényről csak korlátozott információval rendelkezünk.

Az egyik legismertebb módszer a középérték-különbség képlete, amely a Taylor-sor bővítése alapján van levezetve. Ha feltételezzük, hogy a függvény f(x) ismert, akkor a középérték-különbség képlete a következő módon adja meg a deriváltat:

f(x)=f(x+h)f(xh)2hf'(x) = \frac{f(x+h) - f(x-h)}{2h}

Ahol hh a lépésköz, amelyet a numerikus számításhoz választunk. Fontos megjegyezni, hogy ez a képlet csak egy közelítést ad a derivált értékére, mivel a Taylor-sorozatot itt a második derivált felhasználásával eltávolítjuk. Ha hh értéke túl nagy, akkor az eredmény pontatlan lesz, mivel a sorozat trunckálása miatt a hiba növekedni fog. Az optimális lépésköz kiválasztása mindig egyensúlyban van a pontosság és a numerikus hibák között.

Ha például a függvény f(x)=2exx1f(x) = 2e^x - x - 1, és szeretnénk meghatározni annak deriváltját x=1x = 1-nél, akkor a különböző hh értékek mellett végezve el a numerikus differenciálást, a hiba nagysága az hh csökkenésével csökken, de ahogy azt várhatjuk, a túl kis lépésközök esetén a kerekítési hibák növekedhetnek.

Például, ha h=0.01h = 0.01 és h=0.1h = 0.1 között vizsgáljuk a derivált számítását, akkor a következő eredményekre juthatunk:

  • h=0.01h = 0.01 esetén az hiba a számításban az ötödik tizedesjegyig kicsi.

  • Ahogy hh nő, az error is egyre nagyobb lesz, és a mérési pontosság is csökkenni fog.

Ez a jelenség arra utal, hogy a lépésköz optimális megválasztása kulcsfontosságú a pontos numerikus eredmények elérésében. A túl nagy hh értékek esetén a hiba gyorsabban növekszik, míg a túl kicsi lépésközök növelhetik a kerekítési hibát, és nem biztos, hogy javítják az eredményt.

Ha nem rendelkezünk a függvény analitikus kifejezésével, hanem csak egy sor adatpontot (xi,yix_i, y_i) ismerünk, ahol a yiy_i értékek az ismeretlen függvény f(x)f(x) értékeit reprezentálják, akkor más technikákat alkalmazhatunk a derivált meghatározására. Például az egyenletes lépésközön alapuló hárompontos előre differenciálás képlete a következőképpen néz ki:

f(x)=3f(x)+4f(x+h)f(x+2h)2hf'(x) = \frac{ -3f(x) + 4f(x+h) - f(x+2h)}{2h}

Ez a képlet három egymást követő yy értékre alapoz, és azokra a pontokra alkalmazható, ahol a deriváltat keresjük. Ez a módszer hasznos, ha nem ismerjük a függvény explicit kifejezését, hanem csak adataink vannak, például kísérleti mérési pontok formájában.

Az alábbi példánkban az adatokat egy függvényhez rendelhetjük, és az adott xx-értékekhez tartozó deriváltat számíthatunk ki:

pgsql
input no of data points,h
5 1 input x values 5 6 7 8 9 input y values
10.0 14.5 19.5 25.5 32.0
At which data
point derivative is required?

Itt három egymás utáni yy értékre van szükség, hogy meghatározhassuk a deriváltat.

A numerikus differenciálás ezen módszerekkel a fizikai problémák és mérési adatokat érintő kutatások egyik alapvető eszköze, és segíthet a mérési hibák minimalizálásában. Azonban a módszer alkalmazásakor mindig tisztában kell lennünk a hibák forrásaival: a kerekítési hibákkal, a lépésköz optimális megválasztásával, valamint az adatok minőségével.

A különböző módszerek közötti választás során fontos, hogy figyelembe vegyük a kérdéses függvény típusát, az elérhető adatokat, és a kívánt pontosságot. Ha nagyon pontos eredményekre van szükség, érdemes a lépésközöket apróbbra venni, de figyelni kell arra, hogy a kerekítési hiba ne növekedjen túl nagyra.

Ezek a módszerek elengedhetetlenek a mérnöki, fizikai és matematikai alkalmazásokban, ahol gyakran kell gyorsan és pontosan meghatározni a deriváltakat és az elsőrendű differenciálegyenletek megoldásait.