Operacje na tablicach z uwzględnieniem elementów#

Istnieją trzy sposoby przeprowadzenia operacji na tablicach z uwzględnieniem elementów przy użyciu podprogramów i funkcji:

  • procedury elementalne

  • Tablice explicit-shape

  • implementacja operacji dla wektorów oraz pisanie prostych podprogramów opakowujących (które używają reshape wewnętrznie) dla każdego kształtu tablic

W pierwszym sposobie, używane jest słowo kluczowe elemental, aby stworzyć poniższą funkcję:

real(dp) elemental function nroot(n, x) result(y)
  integer, intent(in) :: n
  real(dp), intent(in) :: x
  y = x**(1._dp / n)
end function

Wszystkie argumenty (w środku i na zewnątrz) muszą być skalarne. Funkcja ta może być użyta z tablicami każdego (kompatybilnego) kształtu, na przykład:

print *, nroot(2, 9._dp)
print *, nroot(2, [1._dp, 4._dp, 9._dp, 10._dp])
print *, nroot(2, reshape([1._dp, 4._dp, 9._dp, 10._dp], [2, 2]))
print *, nroot([2, 3, 4, 5], [1._dp, 4._dp, 9._dp, 10._dp])
print *, nroot([2, 3, 4, 5], 4._dp)

Rezultat będzie następujący:

3.0000000000000000
1.0000000000000000        2.0000000000000000        3.0000000000000000        3.1622776601683795
1.0000000000000000        2.0000000000000000        3.0000000000000000        3.1622776601683795
1.0000000000000000        1.5874010519681994        1.7320508075688772        1.5848931924611136
2.0000000000000000        1.5874010519681994        1.4142135623730951        1.3195079107728942

Zazwyczaj n jest parametrem, a x tablicą dowolnego kształtu, jednak jak można zobaczyć w powyższym przykładzie, Fortran nie zwraca na to uwagi dopóki ostateczna operacja ma sens (jeśli jeden argument jest tablicą to pozostałe argumenty też muszą być tablicami o tym samym kształcie lub wartościami skalarnymi). Jeśli warunek ten nie jest spełniony, wyświetli się błąd kompilatora.

Słowo kluczowe elemental implikuje słowo kluczowe pure, tak więc procedura musi być procedurą czystą. Skutkuje to tym, że procedury elementarne mogą używać tylko procedur czystych i nie mają żadnych efektów ubocznych.

Jeśli algorytm procedury elementarnej może zostać przyspieszony używając wewnątrz niej operacji tablicowych lub jeśli z jakichś powodów argumenty są tablicami niekompatybilnych kształtów, należy użyć dwóch pozostałych sposobów. Można sprawić, aby nroot działał na wektorze i napisać prostą funkcję opakowującą dla innych kształtów tablic, np.:

function nroot(n, x) result(y)
  integer, intent(in) :: n
  real(dp), intent(in) :: x(:)
  real(dp) :: y(size(x))
  y = x**(1._dp / n)
end function

function nroot_0d(n, x) result(y)
  integer, intent(in) :: n
  real(dp), intent(in) :: x
  real(dp) :: y
  real(dp) :: tmp(1)
  tmp = nroot(n, [x])
  y = tmp(1)
end function

function nroot_2d(n, x) result(y)
  integer, intent(in) :: n
  real(dp), intent(in) :: x(:, :)
  real(dp) :: y(size(x, 1), size(x, 2))
  y = reshape(nroot(n, reshape(x, [size(x)])), [size(x, 1), size(x, 2)])
end function

I użyć w następujący sposób:

print *, nroot_0d(2, 9._dp)
print *, nroot(2, [1._dp, 4._dp, 9._dp, 10._dp])
print *, nroot_2d(2, reshape([1._dp, 4._dp, 9._dp, 10._dp], [2, 2]))

Rezultat będzie następujący:

3.0000000000000000
1.0000000000000000        2.0000000000000000        3.0000000000000000        3.1622776601683795
1.0000000000000000        2.0000000000000000        3.0000000000000000        3.1622776601683795

Można również użyć tablic explicit-shape, jak w poniższym przykładzie:

function nroot(n, k, x) result(y)
  integer, intent(in) :: n, k
  real(dp), intent(in) :: x(k)
  real(dp) :: y(k)
  y = x**(1._dp / n)
end function

Użyj jak poniżej:

print *, nroot(2, 1, [9._dp])
print *, nroot(2, 4, [1._dp, 4._dp, 9._dp, 10._dp])
print *, nroot(2, 4, reshape([1._dp, 4._dp, 9._dp, 10._dp], [2, 2]))

Rezultat jest taki sam jak wcześniej:

3.0000000000000000
1.0000000000000000        2.0000000000000000        3.0000000000000000        3.1622776601683795
1.0000000000000000        2.0000000000000000        3.0000000000000000        3.1622776601683795