Kiedy chce się obliczyć pochodne numeryczne, metoda przedstawiona przez Bengt Fornberg tutaj (i zgłaszane tutaj ) jest bardzo wygodne (zarówno precyzyjne i proste do wykonania). Jako, że oryginalny artykuł pochodzi z 1988 roku, chciałbym wiedzieć, czy istnieje dziś lepsza alternatywa (jako (lub prawie tak) prosta i bardziej precyzyjna)?
finite-difference
precision
Vincent
źródło
źródło
Odpowiedzi:
Przegląd
Dobre pytanie. Istnieje artykuł zatytułowany „Poprawa dokładności metody różnicowania macierzy dla dowolnych punktów kolokacji” autorstwa R. Baltenspergera. Moim zdaniem nie jest to nic wielkiego, ale ma sens (który był znany już przed pojawieniem się w 2000 r.): Podkreśla znaczenie dokładnego przedstawienia faktu, że pochodna funkcji stałejf(x)=1 powinna być równe zero (dotyczy to dokładnie matematyki, ale niekoniecznie w postaci liczbowej).
Łatwo zauważyć, że wymaga to, aby sumy wierszy n-tej macierzy pochodnychD(n) były równe zero. Często wymusza się to ograniczenie, dostosowując przekątną, tj. Ustawiając D(n)jj:=−∑i=1i≠jNDij.(1) Oczywiste jest, że ta funkcja nie działa dokładnie podczas pracy na komputerze z powodu błędów zaokrągleń w obliczeniach zmiennoprzecinkowych. Bardziej zaskakujące jest to, że błędy te są jeszcze poważniejsze, gdy stosuje się wzory analityczne dla macierzy pochodnych (które są dostępne dla wielu klasycznych punktów kolokacji, np. Gaussa-Lobatto).
Teraz artykuł (i zawarte w nim odnośniki) stwierdza, że błąd pochodnej jest rzędu odchylenia sum wierszy od zera. Dlatego celem jest, aby były one jak najmniejsze numerycznie.
Testy numeryczne
Chodzi o to, że procedura Fornberga wydaje się być pod tym względem całkiem dobra. Na poniższym obrazku porównałem zachowanie dokładnej, tj. Analitycznej, pierwszej macierzy pochodnej i tej uzyskanej przez algorytm Fornberga, dla różnej liczby punktów kolokacji Czebyszewa-Lobatta.
Ponownie, wierząc w stwierdzenie w cytowanym artykule, oznacza to, że algorytm Fornberga da bardziej dokładne wyniki dla pochodnej.
Aby to udowodnić, użyję tej samej funkcji, co w pracy,f(x)=11+x2.(2) En=maxi∈{0,…,n}∣∣∣f′(xi)−∑j=1nDijf(xj)∣∣∣.(3) D~jj=Djj−(∑i=1nDji),for all j.(4)
Wniosek
Podsumowując, metoda Fornberga wydaje się dość dokładna, w przypadku nawet o około 3 rzędy wielkości dokładniejsza niż wyniki z wzorów analitycznych. To powinno być wystarczająco dokładne dla większości aplikacji. Co więcej, jest to niezwykłe, ponieważ Fornberg nie wydaje się wyraźnie uwzględniać tego faktu w swojej metodzie (przynajmniej nie ma wzmianki w dwóch artykułach Fornberga).N=512
Kolejny rząd wielkości można uzyskać dla tego przykładu poprzez proste włączenie równania (4). Ponieważ jest to dość proste podejście i zastosowane tylko raz dla każdej pochodnej, nie widzę powodu, aby go nie używać.
Metoda z pracy Baltenspergera - która wykorzystuje bardziej wyrafinowane podejście do oceny sumy w równaniu (1) w celu zmniejszenia błędów zaokrągleń - daje w przybliżeniu ten sam rząd wielkości błędu. Przynajmniej w tym przykładzie jest to mniej więcej odpowiednik powyższej metody „Dostosowany Fornberg”.
źródło
Zakładając, że próbujesz rozróżnić numeryczną implementację funkcji ciągłej, istnieje wiele metod:
1) Automatyczne różnicowanie. Najdokładniejsza i ogólna metoda. Bolesne dla kodu, wymagające przeciążenia operatora i wyszukiwania zależnego od argumentów. Obciąża użytkownika zrozumieniem tych pojęć. Zmaga się również z wymiennymi osobliwościami, takimi jak różnicowanie cynku przy .x=0
2) Przekształcenie Czebyszewa. Rzuć swoją funkcję na rozpiętość wielomianów Czebyszewa i rozróżnij trzyokresowy nawrót. Super szybki, bardzo dokładny. Wymaga jednak posiadania krótko obsługiwanej domeny zainteresowań; poza wybraną domeną trzyterminowa rekurencja jest niestabilna.[a,b]
3) Różnicowanie skończone. Niedoceniany w 1D; zobacz Wskazówki i triki Nicka Highama w dziedzinie obliczeń numerycznych . Chodzi o to, że jeśli zrównoważysz błąd obcięcia i błąd zaokrąglenia, nie musisz wybierać wielkości kroku; można go wybrać automatycznie. W trybie Boost ten pomysł służy do odzyskania (domyślnie) 6/7 poprawnych cyfr dla typu. (Higham pokazuje tylko pomysł na prostszy przypadek 1/2 poprawnych cyfr, ale pomysł można łatwo rozszerzyć.) Współczynniki pochodzą z wyrównanej tabeli Fornberga, ale wielkość kroku jest wybierana przy założeniu, że funkcję można ocenić na 1ULP precyzja. Wadą jest to, że wymaga 2 ocen funkcji, aby odzyskać połowę cyfr tego typu, 4, aby odzyskać 3/4 cyfr itd. W 1D nie jest to zły interes. W wyższych wymiarach jest katastrofalny.
4) Złożona pochodna krokowa. Użyj . Poświęć aby być jednostką zaokrągleń, a to odzyska prawie każdą poprawność. Jest to jednak trochę oszustwo, ponieważ generalnie trudniej jest zaimplementować funkcję w złożonej płaszczyźnie niż ręcznie kodować jej prawdziwą pochodną. Nadal fajny pomysł i przydatny w pewnych okolicznościach.f′(x)≈I(f(x+ih)) h
źródło
Nie znam nikogo, kto poprawiłby algorytm Fornberga (patrz także jego nieco nowszy artykuł ). Nawiasem mówiąc, wydaje mi się, że postrzeganie jego algorytmu jako sposobu obliczania pochodnych numerycznych jest niewłaściwe. Wszystko, co zrobił, to opracowanie wydajnego algorytmu do obliczania wag dla metod różnic skończonych. Zaletą tej metody jest to, że daje Ci wagi wszystkich pochodnych do żądanej pochodnej za jednym razem.
źródło
Prostszy schemat
Oprócz mojej innej odpowiedzi, która dotyczy bardziej rozszerzenia metody Fornberga, zajmę się tutaj pytaniem o prostsze alternatywy.
W tym celu szkicuję alternatywny schemat, który bardziej bezpośrednio wytwarza współczynniki pochodne interpolacji Lagrangiana. Jego implementacja wymaga tylko kilku wierszy kodu, działa dla dowolnych siatek i według moich pierwszych eksperymentów jest równie dokładna jak Fornberga.
Podstawą implementacji jest wyimaginowana pochodna gdzie jest zmienną rzędu precyzji maszyny. Pochodna wyimaginowanego kroku jest znana z tego, że stabilnie wytwarza wartości pochodnych i nie cierpi na niestabilność liczbową implementacji różnicy skończonej z .f′(x) = 1hIm(f(x+ih)), h h→0
Drugim składnikiem jest wielomian interpolacyjny Lagrange'a na siatce oceniany za pomocą jednej z form barycentrycznych, np. gdzie Aby użyć pochodnej kroku złożonego, należy upewnić się, że te formuły działają również dla złożonych argumenty . Ponadto, dla danej funkcji f (x) i wektora współczynników , oznaczamy wielomian interpolacji poprzez przezLi(x) {x1,…,xN} Li(z) = ⎧⎩⎨⎪⎪1 μiz−xk∑kμkz−xkif z=xiotherwise. μi=1∏k≠i(xi−xk) z fi=f(xi) (x1,fi) P(x;f)=∑i=1NfiLi(x).
Algorytm
Algorytm został naszkicowany poniżej. Ma te same parametry wejściowe i wyjściowe co w Fornbergu, ale jest znacznie bardziej oczywiste.
Wejście:
Inicjalizacja
Algorytm
Podczas gdy :o<ord
Oblicz przez pochodną dla dla wszystko i . Tutaj oznacza ty rząd .D(o+1)ik=CSD(P(xk;D(o)i)) CSD i k
D(o)i i D(o)
Ustaw o = o + 1;
Zdecyduj, co wydrukować :
Wektor współczynników różnic skończonych w punkcie , gdzie . To właśnie robi Fornberg.d(ord) z di=P(z;D(ord)i)
Funkcja interpolacji do pochodnej zamówienia . W tym celu musisz wprowadzić funkcję lub. wartość funkcji w algorytmu.p(ord)(x)=∑Ni=1f(xi)P(x;D(ord)i) f(ord)(x) ord fi xi
Meta-funkcja która zwraca funkcję interpolacji wariantu 2., ale dla dowolnej funkcji która ma być interpolowana w punktach siatki.diff(int ord,function g) g
Osobiście najbardziej podoba mi się wariant 3..
Analiza algorytmu
Algorytmem Fornberga jest . Jeśli znajdę czas, opublikuję więcej wyników empirycznych dotyczących dokładności, stabilności itp.O(ord⋅N2)
źródło
Aby zwiększyć precyzję różnicowania numerycznego, wykonaj następujące czynności:
1) Wybierz swoją ulubioną wysoce precyzyjną „standardową” metodę opartą na rozmiarze kroku h .
2) Oblicz wartość pochodnej metodą wybraną w 1) wiele razy przy różnych, ale rozsądnych rozmiarach kroku h . Za każdym razem możesz wybrać h jako liczbę losową z przedziału (0,5 * H / 10, 1,5 * H / 10), gdzie H jest odpowiednim rozmiarem kroku dla używanej metody.
3) Średnia wyników.
Twój wynik może zyskać 2-3 rzędy wielkości w bezwzględnym błędzie wrt. wynik nie uśredniony.
https://arxiv.org/abs/1706.10219
źródło