Różniczkowanie numeryczne

Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6909
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

Różniczkowanie numeryczne

Post autor: Mariusz M »

Jak zaimplementować pochodną funkcji

Oto mój pomysł

1. Utworzyć trzy ciągi korzystając z ilorazów różnicowych

a) \(\displaystyle{ \frac{f \left( x+h\right)-f \left( x\right) }{h}}\)

Iloraz różnicowy przedni

b) \(\displaystyle{ \frac{f \left( x+h\right)-f \left( x-h\right) }{2h}}\)

Iloraz różnicowy centralny

c) \(\displaystyle{ \frac{f \left( x\right)-f \left( x-h\right) }{h}}\)

Iloraz różnicowy wsteczny

2. Obliczyć granice tych ciągów i jeżeli te granice są równe
to granica ta jest równa pochodnej funkcji w punkcie

I jak to zaimplementować w językach takich jak Pascal czy C
i czy mój pomysł jest dobry
spajder
Użytkownik
Użytkownik
Posty: 735
Rejestracja: 7 lis 2005, o 23:56
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 2 razy
Pomógł: 133 razy

Różniczkowanie numeryczne

Post autor: spajder »

W ten sposób nic nie zdziałasz, bo nie jesteś w stanie numerycznie wyliczyć granicy. Poszukaj:
1. metoda Eulera (prosta)
2. metoda Rungego-Kutty (mnie ciężko było załapać)

jest oczywiście jeszcze sporo innych, ale te dwie są popularne i w miarę łatwo się je implementuje
Awatar użytkownika
Mariusz M
Użytkownik
Użytkownik
Posty: 6909
Rejestracja: 25 wrz 2007, o 01:03
Płeć: Mężczyzna
Lokalizacja: 53°02'N 18°35'E
Podziękował: 2 razy
Pomógł: 1246 razy

Różniczkowanie numeryczne

Post autor: Mariusz M »

Spajder te metody które podałeś dotyczą numerycznego rozwiązywania równań
różniczkowych

Mógłbyś mi objaśnić poniższy kod podobno tutaj biorą granicę z ilorazu centralnego
Ty napisałeś że to niemożliwe

Kod: Zaznacz cały

program NUMERICALDIFFERENTIATIONLIMIT;
{--------------------------------------------------------------------}
{  Alg6'12.pas   Pascal program for implementing Algorithm 6.1-2     }
{                                                                    }
{  NUMERICAL METHODS: Pascal Programs, (c) John H. Mathews 1995      }
{  To accompany the text:                                            }
{  NUMERICAL METHODS for Math., Science & Engineering, 2nd Ed, 1992  }
{  Prentice Hall, Englewood Cliffs, New Jersey, 07632, U.S.A.        }
{  Prentice Hall, Inc.; USA, Canada, Mexico ISBN 0-13-624990-6       }
{  Prentice Hall, International Editions:   ISBN 0-13-625047-5       }
{  This free software is compliments of the author.                  }
{  E-mail address:       in%"mathews@fullerton.edu"                  }
{                                                                    }
{  Algorithm 6.2 (Differentiation Using Extrapolation).              }
{  Section   6.1, Approximating the Derivative, Page 327             }
{--------------------------------------------------------------------}

  uses
    crt;

  const
    Delta = 1E-7;
    Tol = 1E-7;
    Small = 1E-7;
    Big = 1E6;
    Max = 32;
    MaxN = 15;
    MaxV = 34;
    FunMax = 9;

  type
    VECTOR = array[0..MaxV] of real;
    MATRIX = array[0..MaxN, 0..MaxN] of real;
    LETTER = string[1];
    Status = (Done, Working);
    DoSome = (Go, More, Stop);
    LETTERS = string[200];

  var
    FunType, Inum, J, K, M, Meth, N, NS, Sub: integer;
    DL, DR, DS, Error, ErrorS, H, H0, HL, HR, RelErr, Rnum, X: real;
    D, DD, E, F1, F2, HH: VECTOR;
    Ans: CHAR;
    Stat: Status;
    DoMo: DoSome;
    Mess: LETTERS;

  function F (X: real): real;
  begin
    case FunType of
      1: 
        F := SIN(X);
      2: 
        F := COS(X);
      3: 
        F := EXP(X);
      4: 
        begin
          if X = 0 then
            F := 1E-38
          else
            F := LN(ABS(X));
        end;
      5: 
        F := ABS(X);
      6: 
        F := SQRT(ABS(X));
      7: 
        begin
          if X = 0 then
            F := 0
          else
            begin
              if X > 0 then
                F := EXP(LN(X) / 3)
              else
                F := -EXP(LN(ABS(X)) / 3);
            end;
        end;
      8: 
        begin
          if X = 0 then
            F := 0
          else
            begin
              if X > 0 then
                F := EXP(LN(X * X) / 3)
              else
                F := EXP(LN(ABS(X * X)) / 3);
            end;
        end;
      9: 
        F := ABS(X) - X;
    end;
  end;

  procedure PRINTFUNCTION (FunType: integer);
  begin
    case FunType of
      1: 
        WRITELN('F(X)  =  SIN(X)');
      2: 
        WRITELN('F(X)  =  COS(X)');
      3: 
        WRITELN('F(X)  =  EXP(X)');
      4: 
        WRITELN('F(X)  =  LN(X)');
      5: 
        WRITELN('F(X)  =  |X|');
      6: 
        WRITELN('F(X)  =  |X|^1/2');
      7: 
        WRITELN('F(X)  =  X^1/3');
      8: 
        WRITELN('F(X)  =  X^2/3');
      9: 
        WRITELN('F(X)  =  |X| - X');
    end;
  end;

  procedure TAKELIMIT ( {FUNCTION F(X:real): real;}
                  var D, E: VECTOR; var X, H: real; var M: integer);
    var
      J, Min, N: integer;
      R: VECTOR;
  begin
    H := H0;
    Min := 2;
    D[0] := 0.5 * (F(X + H) - F(X - H)) / H;
    F2[0] := F(X + H); {Storing for details}
    F1[0] := F(X - H);
    HH[0] := H;
    for J := 1 to 2 do
      begin
        H := H / 2;
        HH[J] := H;
        D[J] := 0.5 * (F(X + H) - F(X - H)) / H;
        F2[J] := F(X + H); {Storing for details}
        F1[J] := F(X - H);
        E[J] := ABS(D[J] - D[J - 1]);
        R[J] := 2 * E[J] / (ABS(D[J]) + ABS(D[J - 1]) + Small);
        if (ABS(D[J]) < 0.001) then
          Min := 8;
      end;
    N := 1;
    while (((E[N] > E[N + 1]) or (R[N] > Tol)) and (N < Max) and (ABS(D[N]) < Big)) or (N < Min) do
      begin
        H := H / 2;
        HH[N + 2] := H;
        D[N + 2] := 0.5 * (F(X + H) - F(X - H)) / H;
        F2[N + 2] := F(X + H); {Storing for details}
        F1[N + 2] := F(X - H);
        E[N + 2] := ABS(D[N + 2] - D[N + 1]);
        R[N + 2] := 2 * E[N + 2] / (ABS(D[N + 2]) + ABS(D[N + 1]) + Small);
        if (ABS(D[N + 2]) < 0.001) then
          Min := 8;
        N := N + 1;
      end;
    H := 2 * H;
    M := N;
  end;

  procedure EXTRAPOLATE (var X, DE, HL, HR, Error: real; var DD: VECTOR; var N: integer);
    const
      MaxN = 15;
    type
      MATRIX = array[0..MaxN, 0..MaxN] of real;
    var
      J, K: integer;
      RelErr: real;
      D: MATRIX;
    function E4 (L: integer): real;
      var
        I: integer;
        P: real;
    begin
      P := 1;
      for I := 1 to L do
        P := P * 4;
      E4 := P;
    end;
  begin
    J := 1;
    Error := 1;
    RelErr := 1;
    D[0, 0] := (F(X + HR) - F(X - HL)) / (HL + HR);
    DD[0] := D[0, 0];
    HH[0] := HL + HR;
    while (RelErr > Tol) and (Error > Delta) and (J <= MaxN) do
      begin
        HL := HL / 2;
        HR := HR / 2;
        HH[J] := HL + HR;
        D[J, 0] := (F(X + HR) - F(X - HL)) / (HL + HR);
        for K := 1 to J do
          D[J, K] := D[J, K - 1] + (D[J, K - 1] - D[J - 1, K - 1]) / (E4(K) - 1);
        Error := ABS(D[J, J] - D[J - 1, J - 1]);
        RelErr := 2 * Error / (ABS(D[J, J]) + ABS(D[J - 1, J - 1]) + Small);
        DD[J] := D[J, J];
        N := J;
        J := J + 1;
      end;
    DE := D[N, N];
  end;

  procedure GETFUN (var FunType: integer);
    var
      K: integer;
  begin
    CLRSCR;
    WRITELN('                  Choose your function:');
    WRITELN;
    for K := 1 to FunMax do
      begin
        WRITE('          <', K : 2, ' >   ');
        PRINTFUNCTION(K);
        WRITELN;
      end;
    WRITELN;
    WRITE('                  Select  < 1 - ', FunMax : 1, ' >  ? ');
    FunType := 1;
    READLN(FunType);
    if FunType < 1 then
      FunType := 1;
    if FunType > FunMax then
      FunType := FunMax;
  end;

  procedure GETX (Meth: integer; var X: real);
  begin
    CLRSCR;
    WRITELN;
    case Meth of
      1: 
        begin
          WRITELN('     The derivative will be approximated using the limit of a');
          WRITELN;
          WRITELN('sequence of symmetric difference quotients:');
          WRITELN;
          WRITELN('                                                          -n ');
          WRITELN(' lim  D   =   lim  [f(x+h ) - f(x-h )]/2h    where  h  = 2  .');
          WRITELN('n->oo  n     n->oo       n         n     n           n        ');
          WRITELN;
          WRITELN;
          WRITELN('Computation continues until  |D   - D | => |D - D   |  or until');
          WRITELN('                               N+1   N       N   N-1');
          WRITELN;
          WRITELN('consecutive approximations agree to at least six decimal places.');
        end;
      2: 
        begin
          WRITELN('Richardson`s extrapolation is applied to the sequence of difference quotients');
          WRITELN;
          WRITELN('                                              -k   ');
          WRITELN('     { [f(x+h ) - f(x-h )]/2h :  where  h  = 2    }');
          WRITELN('             k         k     k           k         ');
          WRITELN;
          WRITELN('and an approximation to the derivative of the function is determined.');
          WRITELN;
          WRITELN;
          WRITELN('Extrapolation continues until consecutive approximations');
          WRITELN;
          WRITELN;
          WRITELN('agree to at least six decimal places.');
        end;
    end;
    WRITELN;
    WRITELN('     You chose to find the derivative of the function');
    WRITELN;
    WRITE('     ');
    PRINTFUNCTION(FunType);
    WRITELN;
    Mess := '           ENTER the  value  X = ';
    X := 0;
    WRITE(Mess);
    READLN(X);
    Mess := '     ENTER initial size for  H = ';
    H0 := 1;
    WRITE(Mess);
    READLN(H0);
    if H0 < 0 then
      H0 := 1;
    if H0 < 1E-9 then
      H0 := 1E-9;
  end;

  procedure RESULTS (D, E: VECTOR; X, H: real; M: integer);
    var
      B, DL, DLE, DR, DRE: real;
  begin
    CLRSCR;
    WRITELN;
    WRITELN('     The limit of the symmetric difference quotients was found:');
    WRITELN;
    WRITELN('         f`(x)  =   lim   [ f(x+h) - f(x-h) ] / 2h ,');
    WRITELN('                   h -> 0 ');
    WRITELN;
    WRITE('     where  ');
    PRINTFUNCTION(FunType);
    WRITELN;
    WRITELN('     After ', M : 2, ' terms were computed, the');
    WRITELN;
    WRITELN('the step size was reduced to  h = ', H : 15 : 7);
    WRITELN;
    WRITELN('     The approximation for the value of the derivative is:');
    WRITELN;
    WRITELN('         f`(', X : 15 : 7, '  )  = ', D[M] : 15 : 7);
    WRITELN;
    WRITELN('The accuracy is  +-', E[M] : 15 : 7);
    DL := (F(X) - F(X - H)) / H;
    DR := (F(X + H) - F(X)) / H;
    B := ABS(D[M - 1]) + ABS(DL) + ABS(DR) + 0.01;
    DLE := ABS(DL - D[M]) / B;
    DRE := ABS(DR - D[M]) / B;
    if (DL * DR < 0) then
      if (ABS(DL) < 0.005) and (ABS(DR) < 0.005) then
        begin
          DLE := 0;
          DRE := 0;
        end;
    if (DLE > 0.001) or (DRE > 0.001) then
      begin
        WRITELN;
        WRITELN('     The symmetric derivative does not agree with');
        WRITELN('     the left-hand and right-hand derivatives.');
        WRITELN;
        WRITELN('     Left-hand   [ f(x) - f(x-h) ]/h  = ', DL : 15 : 7);
        WRITELN;
        WRITELN('     Right-hand  [ f(x+h) - f(x) ]/h  = ', DR : 15 : 7);
        WRITELN;
        WRITE('Perhaps f`(x) does not exist.  Press the <ENTER> key.');
        READLN(Ans);
        WRITELN;
      end;
    if (ABS(D[M]) > Big) then
      begin
        WRITELN;
        WRITELN('     The difference quotient seems large.');
        WRITELN;
        WRITELN('Perhaps  f`(x)  is infinite.  Press the <ENTER> key.');
        READLN(Ans);
        WRITELN;
      end;
  end;

  procedure RESULTE (X, DS, DL, DR, H, HL, HR, Error: real; NS: integer);
    var
      B: real;
  begin
    CLRSCR;
    WRITELN;
    WRITELN('Richardson`s extrapolation was used on the sequence of difference quotients:');
    WRITELN;
    WRITELN('                                                   -k  ');
    WRITELN('          { [f(x+h ) - f(x-h )]/2h :  where  h  = 2    }');
    WRITELN('                  k         k     k           k         ');
    WRITELN;
    WRITELN('and an approximation was found for the derivative of the function:');
    WRITELN;
    PRINTFUNCTION(FunType);
    WRITELN;
    WRITELN('     After ', NS : 2, ' iterations, the');
    WRITELN;
    WRITELN('step size was reduced to  h = ', H : 15 : 7);
    WRITELN;
    WRITELN('An approximation for the value of the derivative is;');
    WRITELN;
    WRITELN('f`(', X : 15 : 7, '  )  = ', DS : 15 : 7);
    WRITELN;
    WRITELN('The accuracy is  +-', Error : 15 : 7);
    B := 1 + ABS(DL) + ABS(DR);
    if ABS(DR - DL) > 0.001 * B then
      begin
        WRITELN;
        WRITELN('The left-hand and right-hand extrapolations are not equal.');
        WRITELN;
        WRITELN(' lim   [ f(x) - f(x-h) ]/h  = ', DL : 15 : 7);
        WRITELN('h -> 0');
        WRITELN(' lim   [ f(x+h) - f(x) ]/h  = ', DR : 15 : 7);
        WRITELN('h -> 0');
        WRITE('Perhaps f`(x) does not exist.  Press the <ENTER> key.');
        READLN(Ans);
        WRITELN;
      end
  end;

  procedure MESSAGE (var Meth: integer);
  begin
    CLRSCR;
    WRITELN('                 TECHNIQUES FOR NUMERICAL DIFFERENTIATION');
    WRITELN;
    WRITELN;
    WRITELN('          Choose a method for finding the numerical derivative.');
    WRITELN;
    WRITELN;
    WRITELN('          < 1 > Use the limit of symmetric difference quotients');
    WRITELN;
    WRITELN('                to find an approximation to  f`(x):');
    WRITELN;
    WRITELN('                   f`(x)  =   lim   [ f(x+h) - f(x-h) ]/2h');
    WRITELN('                             h -> 0 ');
    WRITELN;
    WRITELN;
    WRITELN('          < 2 > Use Richardson`s extrapolation applied');
    WRITELN;
    WRITELN('                to the sequence of difference quotients:');
    WRITELN;
    WRITELN('                                                        -k  ');
    WRITELN('                { [f(x+h ) - f(x-h )]/2h : where  h  = 2    }');
    WRITELN('                        k         k     k          k         ');
    WRITELN;
    WRITELN;
    Mess := '                Select the method.  < 1 or 2 >  ';
    Meth := 0;
    WRITE(Mess);
    READLN(Meth);
    if Meth < 1 then
      Meth := 1;
    if Meth > 2 then
      Meth := 2;
  end;

  procedure PRINTAPPROXS;
    var
      K: integer;
  begin
    CLRSCR;
    if Meth = 1 then
      begin
        WRITELN;
        WRITELN('       D         =      [ f(x+h )      -      f(x+h ) ]    /     2 h  ');
        WRITELN('        k                      k                   k                k ');
        WRITELN('--------------------------------------------------------------------------------');
        for K := 0 to M do
          begin
            if 0 <= F1[K] then
              WRITELN(D[K] : 15 : 7, '  = [', F2[K] : 15 : 7, '    - ', F1[K] : 15 : 7, ']  /', 2 * HH[K] : 11 : 7)
            else
              WRITELN(D[K] : 15 : 7, '  = [', F2[K] : 15 : 7, '    + ', ABS(F1[K]) : 15 : 7, ']  /', 2 * HH[K] : 11 : 7);
            WRITELN;
            if K mod 11 = 9 then
              begin
                WRITE('                  Press the <ENTER> key.  ');
                READLN(Ans);
                WRITELN;
                WRITELN;
              end;
          end;
        WRITELN;
        WRITE('                  Press the <ENTER> key.  ');
        READLN(Ans);
        WRITELN;
        WRITELN;
        WRITELN;
      end;
    if Meth = 2 then
      begin
        WRITELN;
        WRITELN('           k             h                   D  ');
        WRITELN('                          k                   k ');
        WRITELN('         ---------------------------------------------------');
        WRITELN;
        for K := 0 to NS do
          begin
            WRITELN('          ', K : 2, '     ', HH[K] / 2 : 15 : 7, '     ', DD[K] : 15 : 7);
            WRITELN;
            if K mod 11 = 9 then
              begin
                WRITE('                  Press the <ENTER> key.  ');
                READLN(Ans);
                WRITELN;
                WRITELN;
              end;
          end;
        WRITELN;
        WRITE('                  Press the <ENTER> key.  ');
        READLN(Ans);
        WRITELN;
        WRITELN;
      end;
  end;

begin                                            {Begin Main Program}
  MESSAGE(Meth);
  DoMo := Go;
  while (DoMo = Go) or (DoMo = More) do
    begin
      if DoMo = More then
        begin
          WRITELN;
          WRITE('Do  you  want  to change  the method ?  <Y/N>  ');
          READLN(Ans);
          WRITELN;
          if (Ans = 'y') or (Ans = 'Y') then
            MESSAGE(Meth);
        end;
      GETFUN(FunType);
      Stat := Working;
      while Stat = Working do
        begin
          GETX(Meth, X);
          case Meth of
            1: 
              begin
                TAKELIMIT(D, E, X, H, M);
                RESULTS(D, E, X, H, M);
              end;
            2: 
              begin
                H := H0;
                HL := H0;
                HR := 0;
                EXTRAPOLATE(X, DL, HL, HR, Error, DD, N);
                HL := 0;
                HR := H0;
                EXTRAPOLATE(X, DR, HL, HR, Error, DD, N);
                HL := H0;
                HR := H0;
                EXTRAPOLATE(X, DS, HL, HR, ErrorS, DD, NS);
                RESULTE(X, DS, DL, DR, H, HL, HR, ErrorS, NS);
              end;
          end;
          WRITELN;
          WRITE('Want  to see  all the approximations ?  <Y/N>  ');
          READLN(Ans);
          WRITELN;
          if (Ans = 'Y') or (Ans = 'y') then
            PRINTAPPROXS;
          WRITELN;
          WRITE('Want evaluate f`(x) at another point ?  <Y/N>  ');
          READLN(Ans);
          WRITELN;
          if (Ans <> 'Y') and (Ans <> 'y') then
            Stat := Done;
        end;
      WRITELN;
      WRITE('Do you want to try  another function ?  <Y/N>  ');
      READLN(Ans);
      WRITELN;
      if (Ans = 'Y') or (Ans = 'y') then
        DoMo := More
      else
        DoMo := Stop;
    end;
end.     
                                       {End of Main Program}
xiikzodz
Użytkownik
Użytkownik
Posty: 1874
Rejestracja: 4 paź 2008, o 02:13
Płeć: Kobieta
Lokalizacja: Lost Hope
Podziękował: 28 razy
Pomógł: 502 razy

Różniczkowanie numeryczne

Post autor: xiikzodz »

Mozna z uzyciem ilorazu roznicowego. Na przyklad pochodna funkcji \(\displaystyle{ f(x)}\) w punkcie \(\displaystyle{ x_0=0}\) mozna przyblizyc wartoscia \(\displaystyle{ \frac{f(x_0+0.01)-f(x)}{0.01}}\) i bedzie to dobre przyblizenie dla \(\displaystyle{ f(x)=x^2}\), lecz marne dla \(\displaystyle{ f(x)=(2x)^{10}}\). Znaczy sie z jednej strony chcemy w mozliwie malej liczbie krokow dobrze przyblizyc pochodna, a z drugiej strony chcemy uniknac bledow numerycznych wynikajacych np. z dzielenia przez liczby bliskie zeru. Ponizej ustalamy sobie zawczasu dokladnosc. Nie jest to taka dokladnosc w sensie bledu w wyznaczeniu pochodnej, tylko nominalna/umowna dokladnosc systemu pozycyjnego w maszynie.

Liczymy f'(x):

Kod: Zaznacz cały

const dokladnosc=0.01;

float diff(x)
{
	delta=1;
	aktualny=1;
	poprzedni=0;
	while (delta>dokladnosc)
	{
		poprzedni=aktualny;
		aktualny=f(x+delta)+aktualny-aktualny*delta;
		delta=min(delta/2,abs(aktualny-poprzedni));
	}//while
	return aktualny;
}//diff
Ciekawe, czy dziala...
ODPOWIEDZ