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