Java - algoritmy numerického derivovania: Rozdiel medzi revíziami

Z Kiwiki
Skočit na navigaci Skočit na vyhledávání
 
Riadok 220: Riadok 220:
 
</source>
 
</source>
  
Na nasledujúcom obrázku je červenou farbou nakreslená funkcia <math>cos(2x)-x</math> a červenou farbou je vykreslená prvá derivácia.
+
Na nasledujúcom obrázku je červenou farbou nakreslená funkcia <math>cos(2x)-x</math> a oranžovou farbou je vykreslená prvá derivácia.
  
 
[[Súbor:numerica derivacia4- aplikacia.png|center|thumb|400px|Riešenie numerickej derivácie]]
 
[[Súbor:numerica derivacia4- aplikacia.png|center|thumb|400px|Riešenie numerickej derivácie]]

Aktuálna revízia z 16:28, 5. marec 2013

Medzi ďalšie numerické algoritmy patria algoritmy numerického derivovania. Nasledujúce algoritmy budeme dopĺňať do triedy Solver. V nasledujúcom texte budú ukázané 2 metódy numerického derivovania. Prvá metóda je priamo odvodená z definície derivácie a druhá metóda používa rozdielové diferencie.

Algoritmy numerického derivovania

Základná numerická derivácia

Drivácia funkcie f(x) je definovaná ako:

[math]{f}'\left( x \right)=\underset{h\to 0}{\mathop{\lim }}\,\frac{f\left( x+h \right)-f\left( x \right)}{h}[/math]

Z tejto definíce budeme vychádzať aj pri implementácii algoritmu derivovania. Limitu v predchádzajúcom vzorci nahradíme tým, že do premennej h dosadíme hodnotu blížiacu sa k nule.

V triede Solver sme doplnili premennú h, ktorej význam je najlepšie vidieť z predchádzajúceho vzorca. V nasledujúcom zdrojovom kóde je uvedený aj konštruktor triedy Solver, v ktorom je doplnená inicializácie premennej h. Ešte poznamenajme, že počítame deriváciu funkcie f, ktorá je členským objektom v triede Solver.

public class Solver {

    private FunkceM f;
    public double h;

    public Solver(FunkceM f) {
        this.f = f;
        this.h = 0.0000001;
    }

//...

    public double derivacia1(double x0) {
        return (this.f.hodnota(x0 + this.h) - this.f.hodnota(x0)) / this.h;
    }

//...

}

Derivácia pomocou rozdielových diferencií

Prvá derivácie funkcie f(x) sa dá definovať aj nasledovne:


[math]{f}'\left( {{x}_{0}} \right)=\frac{1}{h}\left( \frac{\Delta {{y}_{-1}}+\Delta {{y}_{1}}}{2}-\frac{1}{6}\frac{{{\Delta }^{3}}{{y}_{-1}}-{{\Delta }^{3}}{{y}_{1}}}{2} \right)[/math]

kde [math]\Delta{y}[/math] sú rozdielové diferencie. Tieto diferencie sa dajú znázorniť nasledovne:

Rozdielové diferencie

Pre výpočet jednotlivých diferencií je potrebné poznať hodnotu h. Jej význam je rovnaký ako v predchádzajúcom príklade. Pre výpočet diferencií platia vzťahy:


[math]\begin{align} & \Delta {{y}_{-2}}=f\left( {{x}_{0}}-h \right)-f\left( {{x}_{0}}-2h \right) \\ & \Delta {{y}_{-1}}=f\left( {{x}_{0}} \right)-f\left( {{x}_{0}}-h \right) \\ & \Delta {{y}_{1}}=f({{x}_{0}}+h)-f\left( {{x}_{0}} \right) \\ & \Delta {{y}_{2}}=f({{x}_{0}}+2h)-f\left( {{x}_{0}}+h \right) \\ \end{align}[/math]


[math]\begin{align} & {{\Delta }^{2}}{{y}_{-1}}=\Delta {{y}_{-1}}-\Delta {{y}_{-2}} \\ & {{\Delta }^{2}}{{y}_{0}}=\Delta {{y}_{1}}-\Delta {{y}_{-1}} \\ & {{\Delta }^{2}}{{y}_{1}}=\Delta {{y}_{2}}-\Delta {{y}_{1}} \\ \end{align}[/math]


[math]\begin{align} & {{\Delta }^{3}}{{y}_{-1}}={{\Delta }^{2}}{{y}_{0}}-{{\Delta }^{2}}{{y}_{-1}} \\ & {{\Delta }^{3}}{{y}_{1}}={{\Delta }^{2}}{{y}_{1}}-{{\Delta }^{2}}{{y}_{0}} \\ \end{align}[/math]


[math]{{\Delta }^{4}}{{y}_{0}}={{\Delta }^{3}}{{y}_{1}}-{{\Delta }^{3}}{{y}_{-1}}\,[/math]

Na nasledujúcom obrázku je znázornený geometrický význam rozdielových diferencií.

Geometrický význam rozdielových diferencií

Triedu Solver doplníme nasledovne:

    public double derivacia2(double x0) {
        double delta[] = new double[5];
        delta[0] = this.f.hodnota(x0 - 2 * this.h);
        delta[1] = this.f.hodnota(x0 - this.h);
        delta[2] = this.f.hodnota(x0);
        delta[3] = this.f.hodnota(x0 + this.h);
        delta[4] = this.f.hodnota(x0 + 2 * this.h);

        // vypocet delta
        for (int i = 0; i < 4; i++) {
            delta[i] = delta[i + 1] - delta[i];
        }
        double derivace = (delta[1] + delta[2]) / 2;

        // vypocet delta^2
        for (int i = 0; i < 3; i++) {
            delta[i] = delta[i + 1] - delta[i];
        }

        // vypocet delta^3
        for (int i = 0; i < 2; i++) {
            delta[i] = delta[i + 1] - delta[i];
        }

        derivace -= (delta[0] - delta[1]) / 12;

        return derivace / this.h;
    }

Poznámky k zdrojovému kódu:

  • pre výpočet diferencií [math]\Delta{y}[/math] sme použili jednorozmerné pole derivace
  • v jednotlivých cyklch for počítame [math]\Delta{y}[/math], [math]\Delta^2{y}[/math] a [math]\Delta^3{y}[/math]
  • V poslednom kroku dosad9me diferencie do vzorca na výpočet derivácie.

Použitie metód derivácie v aplikácii

Vo vzorovej aplikácii pridáme na kartu 'Drivácia' komponenty podľa nasledujúceho obrázku:

Návrh vizuálnej podoby aplikácie v časti derivácia

Opis komponentov:

buttonGroup

  • do aplikácie pridáme nevizuálny komponent buttonGroup
  • názov komponentu derivaciaGroup

RadioButton

  • Derivácia 1:
    • názov komponentu rbDerivacia1,
    • vlastnosť buttonGroup: derivaciaGroup
  • Derivácia 2:
    • názov komponentu rbDerivacia2
    • vlastnosť buttonGroup: derivaciaGroup

textField

  • Slúži na zadanie bodu x0, v ktorom budeme počítať deriváciu
    • názov komponentu: textX0

label

  • Zobrazenie výsledku derivácie (je pod komponentom textX0). Na predchádzajúcom obrázku má hodnotu 0.000 .
    • názov komponentu: labelDerivacia
  • Ostatné komponenty label slúžia iba na zobrazenie textu, ktorý sa počas behu programu nemení.

button

  • tlačidlo 'Derivuj!' slúži na spustenie výpočtu derivácie
    • názov komponentu: btnDerivuj
    • udalosť tlačidla: actionPerformed

checkBox

  • Zaškrtávacie tlačidlo využijeme pri možnsti vykresliť priebeh derivácie
    • názov komponentu: cbKresliDerivaciu


Obsluha tlačítka 'Derivuj!':

    private void btnDerivujActionPerformed(java.awt.event.ActionEvent evt) {
        double x0 = Double.valueOf(textX0.getText());       
        if (rbDerivacia1.isSelected()) {
            x0 = s.derivacia1(x0);
        }
        if (rbDerivacia1.isSelected()) {
            x0 = s.derivacia2(x0);
        }
        labelDerivacia.setText(String.valueOf(x0));
    }


Vykreslenie priebehu derivácie.

Zmena, resp. doplnenie kódu bude v metóde tlcKresliActionPerformed, ktorá sa stará o vykreslenie matematickej funkcie. V nasledujpcom zdrojovom kóde je uvedený výpis celej metódy tlcKresliActionPerformed.

    private void tlcKresliActionPerformed(java.awt.event.ActionEvent evt) {                                          
        int sirka, vyska; //sirka a vyska panelu na kreslenie
        sirka = panel.getWidth();
        vyska = panel.getHeight();
        t.setSize(sirka, vyska);

        g = panel.getGraphics();
        g.setColor(Color.GRAY);
        g.drawLine(0, vyska / 2, sirka, vyska / 2);
        g.drawLine(sirka / 2, 0, sirka / 2, vyska);

        g.setColor(Color.RED);
        double x1, y1, x2, y2 = 0;
        int X1, Y1, X2, Y2;
        x1 = -t.getStrana();
        y1 = f.hodnota(x1);
        for (x2 = -t.getStrana(); x2 < t.getStrana(); x2 += t.getKrok()) {
            y2 = f.hodnota(x1);
            X1 = t.getX(x1);
            X2 = t.getX(x2);
            Y1 = t.getY(y1);
            Y2 = t.getY(y2);
            g.drawLine(X1, Y2, X2, Y2);

            x1 = x2;
            y1 = y2;
        }

        // doplnenie vykreslovania priebehu prvej derivacie
        if (cbKresliDerivaciu.isSelected()) {
            g.setColor(Color.ORANGE);
            x1 = -t.getStrana();
            y1 = s.derivacia2(x1);
            
            for (x2 = -t.getStrana() + t.getKrok(); x2 < t.getStrana(); x2 += t.getKrok()) {
                if (rbDerivacia1.isSelected()) {
                    y2 = s.derivacia1(x2);
                }
                if (rbDerivacia2.isSelected()) {
                    y2 = s.derivacia2(x2);
                }
                g.drawLine(t.getX(x1), t.getY(y1), t.getX(x2), t.getY(y2));
                x1 = x2;
                y1 = y2;
            }
        }
    }

Na nasledujúcom obrázku je červenou farbou nakreslená funkcia [math]cos(2x)-x[/math] a oranžovou farbou je vykreslená prvá derivácia.

Riešenie numerickej derivácie