Metoda Newtona do rozwiązywania równania nieliniowego

0

Zaimplementowałem w Javę metodę Newtona do rozwiązania równania nieliniowego
user image

Natrafiłem na taką ciekawą rzecz, iż dla dla x0 będącego liczbą nieparzystą zawsze mam błąd względny = 0, natomiast dla x0 parzystego błąd jest > 0, ale taki sam dla wszystkich liczb parzystych oraz jest ta sama ilość obrotów pętli (przy tym samym epsilonie), co jest dla dziwne i nie wiem czy popełniłem błąd w programie, czy tak ma być

Oto kod:

package newton;

/**
 * Netwon's method implementation
 */
public class Newton {

    private static final double realRoot = 1.0;

    public static double f(double x) {
        return 2.0 + Math.cos((Math.PI / 2.0) * x) - 2.0 * x; // funkcja f
    }

    public static double fp(double x) {
        return -1 / 2 * Math.PI * Math.sin((Math.PI * x) / 2) - 2; // pochodna f
    }

    public static double round(double value, int places) {
        if (places < 0) {
            throw new IllegalArgumentException();
        }

        long factor = (long) Math.pow(10, places);
        value = value * factor;
        long tmp = Math.round(value);
        return (double) tmp / factor;
    }

    public static double getRelativeError(double x) {
        return Math.abs((x - realRoot) / realRoot);
    }

    public static void main(String[] args) {
        double x0, epsilon, h;
        epsilon = 0.001;
        x0 = 1;
        int n = 0;
        do {
            h = -(f(x0) / fp(x0));
            x0 = x0 + h;
            n++;
        } while (Math.abs(h) > epsilon);
        System.out.println("Newton");
        System.out.println("x=" + x0);
        System.out.println("n=" + n);
        double relativeError = getRelativeError(x0);
        System.out.println("Blad wzgledny: " + relativeError * 100 + "%");
    }

}

0

Rysowanie wykresów krzywikiem się do czegoś przydało. Cosinus ma wartość 0 w pi/2 ;), wiec to normalne. A w Pi ma pochodną czytaj nachylenie równą zero, a własnie nachylenia używasz by w metodzie newtona, pochodna z funkcji liniowej jest stała, a ze stałej zerowa ;), a ponieważ cos jest okresowy to powinieneś otrzymać wynik co najwyżej na kilka możliwych sposobów(dla liczb całkowitych).
Wyniki przewidywalne czyli najlepsze :).
Policz to samo dla f(x) = cos(1/(2pi)x) -0.001cos(1/(2pi)x). Napisz w ilu iteracjach policzyło dla parzystych;)

0

Masz błędny wzór na pochodną. Powinno być tak

-1 / 2.0 * Math.PI * Math.sin((Math.PI * x) / 2) - 2;

lub tak

-0.5 * Math.PI * Math.sin((Math.PI * x) / 2) - 2;
0

Nie opłynąłem tylko właściwości tej funkcji będą takie same ;) bardzo można łatwo to narysować. Niestety tu taj się nie da.
Metoda newtona działa tak: kolejny punkt do sprawdzenia to punkt przecięcia z zerem gdyby funkcja była nachylona tak jak jest nachylona w obecnie sprawdzanym punkcie.
Dla liczb nie parzystych nachylenie(+/-pochodna) TEGO cosinusa wynosi +/- 1 a moduł pochodnej części liniowej wynosi |2|. Czyli wynosi +/-1 lub +/- 3. Ponieważ wszystkie współczynnik są liczbami całkowitymi to każdy krok jest przesunięty od poprzedniego o pewną liczbę nieparzystą, czyli w cosinus zawsze się z zeruje(zakładam ze wiesz dlaczego), co bardzo wszystko upraszcza. W tym momencie algorytm wygląda tak: skaczesz sobie o -/+ 3 lub -/+1 od pewnej wartości całkowitej aż trafisz w rozwiązanie fuckji y = -2x +2 - cosinus wynosi zawsze 0 wiec można go pominąć. Ponieważ sprawdzasz tylko liczby całkowite to siłą rzeczy musisz trafić w rozwiązanie bardzo dokładnie +/- (błąd reprezentacji(Pi i cosinusa) + powielenie go w iteracjach).
W przypadku licz parzystych pochodna ma zawsze wartość -2, a jej przedłużenie zawsze przetnie się z ze sprawdzaną fukcją w tym samym punkcie. Tak jak pisałem skończona(nawet bardzo) liczba przypadków.

Ten błąd z brakiem konwersji do double nie zmieniał nic w przypadku liczb parzystych bo i tak było by tam 0. A w przypadku liczb nie parzystych redukował równanie pochodnej do uwaga uwaga y = -2x +2 ;) różnica jest taka że znajdował wynik w jednym kroku.

0

Po poprawieniu błędnego wzoru na pochodną, opisane przez autora objawy znikają. A więc Twoje wyjaśnienie tych objawów było błędne.

0
bogdans napisał(a):

Masz błędny wzór na pochodną. Powinno być tak

-1 / 2.0 * Math.PI * Math.sin((Math.PI * x) / 2) - 2;

lub tak

-0.5 * Math.PI * Math.sin((Math.PI * x) / 2) - 2;

zmieniłem pochodną na
-1 / 2.0 * Math.PI * Math.sin((Math.PI * x) / 2) - 2
i jako x przyjmuję 10.0, 100.0, 1000.0, 10000.0
epsilon = 1e-5

W takim układzie dla każdego x błąd wynosi 0...

Jednak dla 1e-4 błąd istnieje, także chyba ok

1 użytkowników online, w tym zalogowanych: 0, gości: 1