Fortran
Tablice
Szukaj…
Podstawowa notacja
Dowolny typ może być zadeklarowany jako tablica za pomocą atrybutu wymiaru lub poprzez bezpośrednie wskazanie dimension
( dimension
) tablicy:
! One dimensional array with 4 elements
integer, dimension(4) :: foo
! Two dimensional array with 4 rows and 2 columns
real, dimension(4, 2) :: bar
! Three dimensional array
type(mytype), dimension(6, 7, 8) :: myarray
! Same as above without using the dimension keyword
integer :: foo2(4)
real :: bar2(4, 2)
type(mytype) :: myarray2(6, 7, 8)
Ten ostatni sposób deklarowania tablicy wielowymiarowej umożliwia deklarację tablic wymiarów / wymiarów tego samego typu w jednym wierszu w następujący sposób
real :: pencil(5), plate(3,-2:4), cuboid(0:3,-10:5,6)
Maksymalna dozwolona ranga (liczba wymiarów) to 15 w standardzie Fortran 2008 i była wcześniej 7.
Fortran przechowuje tablice w kolejności od głównych kolumn . Oznacza to, że elementy bar
są przechowywane w pamięci w następujący sposób:
bar(1, 1), bar(2, 1), bar(3, 1), bar(4, 1), bar(1, 2), bar(2, 2), ...
W Fortranie numeracja tablic zaczyna się domyślnie od 1 , w przeciwieństwie do C, który zaczyna się od 0 . W rzeczywistości w Fortranie można jawnie określić górne i dolne granice dla każdego wymiaru:
integer, dimension(7:12, -3:-1) :: geese
Deklaruje tablicę kształtu (6, 3)
, której pierwszym elementem są geese(7, -3)
.
Dolne i górne granice wzdłuż 2 (lub więcej) wymiarów mogą być dostępne przez funkcje wewnętrzne ubound
i lbound
. Rzeczywiście lbound(geese,2)
zwróci -3
, podczas gdy ubound(geese,1)
zwróci 12
.
Rozmiar tablicy można uzyskać poprzez wewnętrzny size
funkcji. Na przykład size(geese, dim = 1)
zwraca rozmiar pierwszego wymiaru, który wynosi 6.
Tablice alokowalne
Tablice mogą mieć atrybut alokowalny :
! One dimensional allocatable array
integer, dimension(:), allocatable :: foo
! Two dimensional allocatable array
real, dimension(:,:), allocatable :: bar
To deklaruje zmienną, ale nie przydziela dla niej miejsca.
! We can specify the bounds as usual
allocate(foo(3:5))
! It is an error to allocate an array twice
! so check it has not been allocated first
if (.not. allocated(foo)) then
allocate(bar(10, 2))
end if
Gdy zmienna nie jest już potrzebna, można ją zwolnić :
deallocate(foo)
Jeśli z jakiegoś powodu instrukcja allocate
nie powiedzie się, program się zatrzyma. Można temu zapobiec, jeśli status jest sprawdzany za pomocą słowa kluczowego stat
:
real, dimension(:), allocatable :: geese
integer :: status
allocate(geese(17), stat=status)
if (stat /= 0) then
print*, "Something went wrong trying to allocate 'geese'"
stop 1
end if
Instrukcja deallocate
ma również słowo kluczowe stat
:
deallocate (geese, stat=status)
status
jest zmienną całkowitą, której wartość wynosi 0, jeśli alokacja lub dezalokacja przebiegły pomyślnie.
Konstruktory tablic
Wartość tablicy rangi 1 można utworzyć za pomocą konstruktora tablic ze składnią
(/ ... /)
[ ... ]
Forma [...]
została wprowadzona w Fortran 2003 i jest ogólnie uważana za bardziej czytelną, szczególnie w złożonych wyrażeniach. Ten formularz jest używany wyłącznie w tym przykładzie.
Wartości występujące w konstruktorze tablicowym mogą być wartościami skalarnymi, wartościami tablic lub pętlami domyślnymi.
Typ i parametry typu zbudowanej tablicy są zgodne z wartościami w konstruktorze tablicy
[1, 2, 3] ! A rank-1 length-3 array of default integer type
[1., 2., 3.] ! A rank-1 length-3 array of default real type
["A", "B"] ! A rank-1 length-2 array of default character type
integer, parameter :: A = [2, 4]
[1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements
integer i
[1, (i, i=2, 5), 6] ! A rank-1 length-6 array of default integer type with an implied-do
W powyższych formularzach wszystkie podane wartości muszą być tego samego typu i parametru typu. Mieszanie typów lub parametrów typów jest niedozwolone. Poniższe przykłady są nieprawidłowe
[1, 2.] ! INVALID: Mixing integer and default real
[1e0, 2d0] ! INVALID: Mixing default real and double precision
[1., 2._dp] ! INVALID: Allowed only if kind `dp` corresponds to default real
["Hello", "Frederick"] ! INVALID: Different length parameters
Aby zbudować tablicę przy użyciu różnych typów, należy podać specyfikację typu tablicy
[integer :: 1, 2., 3d0] ! A default integer array
[real(dp) :: 1, 2, 3._sp] ! A real(dp) array
[character(len=9) :: "Hello", "Frederick"] ! A length-2 array of length-9 characters
Ta ostatnia forma tablic znaków jest szczególnie wygodna, aby uniknąć wypełniania miejsca, na przykład alternatywy
["Hello ", "Frederick"] ! A length-2 array of length-9 characters
Rozmiar tablicy o nazwie stałej może wynikać z konstruktora tablicy używanego do ustawiania jej wartości
integer, parameter :: ids(*) = [1, 2, 3, 4]
a dla typów sparametryzowanych długość można przyjąć parametr długości
character(len=*), parameter :: names(*) = [character(3) :: "Me", "You", "Her"]
Specyfikacja typu jest również wymagana w konstrukcji tablic zerowej długości. Od
[ ] ! Not a valid array constructor
typu i parametrów typu nie można ustalić na podstawie nieistniejącego zestawu wartości. Aby utworzyć domyślną tablicę liczb całkowitych o zerowej długości:
[integer :: ]
Konstruktory tablic konstruują tylko tablice rangi 1. Czasami, na przykład przy ustawianiu wartości nazwanej stałej, w wyrażeniu wymagane są również tablice wyższej rangi. Tablice wyższej rangi można pobrać z wyniku reshape
za pomocą skonstruowanej tablicy rangi 1
integer, parameter :: multi_rank_ids(2,2) = RESHAPE([1,2,3,4], shape=[2,2])
W konstruktorze tablicowym wartości tablicy w kolejności elementów z dowolnymi tablicami na liście wartości są takie, jakby poszczególne elementy były podawane w kolejności elementów tablicy. Tak więc wcześniejszy przykład
integer, parameter :: A = [2, 4]
[1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements
jest równa
[1, 2, 4, 3] ! With the array written out in array element order
Ogólnie wartości w konstruktorze mogą być dowolnymi wyrażeniami, w tym konstruktorami tablic zagnieżdżonych. Aby taki konstruktor tablicowy spełniał określone warunki, takie jak wyrażenie stałe lub wyrażenie specyfikacji, ograniczenia mają zastosowanie do wartości składowych.
Chociaż nie jest to konstruktor tablicowy, pewne wartości tablicowe można również wygodnie utworzyć za pomocą funkcji wewnętrznej spread
. Na przykład
[(0, i=1,10)] ! An array with 10 default integers each of value 0
jest również wynikiem odwołania do funkcji
SPREAD(0, 1, 10)
Specyfikacja natury tablic: ranga i kształt
Atrybut dimension
obiektu określa, że obiekt ten jest tablicą. W Fortran 2008 istnieje pięć rodzajów tablic: 1
- wyraźny kształt
- przybrał kształt
- przyjęty rozmiar
- odroczony kształt
- domniemany kształt
Weź trzy tablice rangi 1 2
integer a, b, c
dimension(5) a ! Explicit shape (default lower bound 1), extent 5
dimension(:) b ! Assumed or deferred shape
dimension(*) c ! Assumed size or implied shape array
Dzięki nim można zobaczyć, że dalszy kontekst jest wymagany do pełnego określenia natury tablicy.
Wyraźny kształt
Wyraźna tablica kształtów jest zawsze kształtem deklaracji. O ile tablica nie jest zadeklarowana jako lokalna dla podprogramu lub konstrukcji block
, kształt definiujący granice musi być wyrażeniami stałymi. W innych przypadkach jawna tablica kształtów może być obiektem automatycznym, wykorzystującym zakresy, które mogą się różnić przy każdym wywołaniu podprogramu lub block
.
subroutine sub(n)
integer, intent(in) :: n
integer a(5) ! A local explicit shape array with constant bound
integer b(n) ! A local explicit shape array, automatic object
end subroutine
Przyjęty kształt
Przyjęta tablica kształtów jest fikcyjnym argumentem bez atrybutu allocatable
lub pointer
. Taka tablica bierze swój kształt z rzeczywistego argumentu, z którym jest skojarzona.
integer a(5), b(10)
call sub(a) ! In this call the dummy argument is like x(5)
call sub(b) ! In this call the dummy argument is like x(10)
contains
subroutine sub(x)
integer x(:) ! Assumed shape dummy argument
end subroutine sub
end
Gdy fikcyjny argument przybierze kształt, zakres odwołujący się do procedury musi mieć jawny interfejs dla tej procedury.
Zakładany rozmiar
Przyjęta tablica rozmiarów jest fikcyjnym argumentem, którego rozmiar przyjmuje się z argumentu rzeczywistego.
subroutine sub(x)
integer x(*) ! Assumed size array
end subroutine
Tablice założonych rozmiarów zachowują się bardzo inaczej niż tablice założonych kształtów, a różnice te są udokumentowane w innym miejscu.
Odroczony kształt
Odroczona tablica kształtów to tablica, która ma atrybut allocatable
lub pointer
. Kształt takiej tablicy zależy od jej alokacji lub przypisania wskaźnika.
integer, allocatable :: a(:)
integer, pointer :: b(:)
Sugerowany kształt
Domniemana tablica kształtów to nazwana stała, która bierze swój kształt z wyrażenia użytego do ustalenia jego wartości
integer, parameter :: a(*) = [1,2,3,4]
Implikacje tych deklaracji tablicowych dla argumentów fikcyjnych należy udokumentować w innym miejscu.
1 Specyfikacja techniczna rozszerzająca Fortran 2008 dodaje szósty charakter: zakładana ranga. Nie jest to tutaj omówione.
2 Można je odpowiednio zapisać jako
integer, dimension(5) :: a
integer, dimension(:) :: b
integer, dimension(*) :: c
lub
integer a(5)
integer b(:)
integer c(*)
Całe tablice, elementy tablicy i sekcje tablicy
Rozważ tablicę zadeklarowaną jako
real x(10)
Następnie mamy trzy aspekty zainteresowania:
- Cała tablica
x
; - Elementy tablicy, takie jak
x(1)
; - Sekcje tablic, takie jak
x(2:6)
.
Całe tablice
W większości przypadków cała tablica x
odnosi się do wszystkich elementów tablicy jako pojedynczej jednostki. Może występować w instrukcjach wykonywalnych, takich jak print *, SUM(x)
, print *, SIZE(x)
lub x=1
.
Cała tablica może odwoływać się do tablic, które nie są jawnie ukształtowane (takie jak x
powyżej):
function f(y)
real, intent(out) :: y(:)
real, allocatable :: z(:)
y = 1. ! Intrinsic assignment for the whole array
z = [1., 2.,] ! Intrinsic assignment for the whole array, invoking allocation
end function
Tablica o założonym rozmiarze może również pojawiać się jako cała tablica, ale tylko w ograniczonych okolicznościach (do udokumentowania w innym miejscu).
Elementy tablicy
Określono, że element tablicy daje indeksy całkowite, po jednym dla każdej rangi tablicy, oznaczające lokalizację w całej tablicy:
real x(5,2)
x(1,1) = 0.2
x(2,4) = 0.3
Elementem tablicy jest skalar.
Sekcje tablic
Sekcja tablicowa to odniesienie do wielu elementów (być może tylko jednego) całej tablicy, przy użyciu składni obejmującej dwukropki:
real x(5,2)
x(:,1) = 0. ! Referring to x(1,1), x(2,1), x(3,1), x(4,1) and x(5,1)
x(2,:) = 0. ! Referring to x(2,1), x(2,2)
x(2:4,1) = 0. ! Referring to x(2,1), x(3,1) and x(4,1)
x(2:3,1:2) = 0. ! Referring to x(2,1), x(3,1), x(2,2) and x(3,2)
x(1:1,1) = 0. ! Referring to x(1,1)
x([1,3,5],2) = 0. ! Referring to x(1,2), x(3,2) and x(5,2)
Ostatni formularz powyżej używa indeksu wektorowego . Jest to przedmiotem szeregu ograniczeń poza innymi sekcjami tablicy.
Każda sekcja tablicy jest tablicą, nawet jeśli odwołuje się tylko do jednego elementu. To znaczy x(1:1,1)
to tablica rangi 1, a x(1:1,1:1)
to tablica rangi 2.
Sekcje tablicy zasadniczo nie mają atrybutu całej tablicy. W szczególności gdzie
real, allocatable :: x(:)
x = [1,2,3] ! x is allocated as part of the assignment
x = [1,2,3,4] ! x is dealloacted then allocated to a new shape in the assignment
przydzial
x(:) = [1,2,3,4,5] ! This is bad when x isn't the same shape as the right-hand side
nie jest dozwolone: x(:)
, chociaż sekcja tablicy ze wszystkimi elementami x
, nie jest tablicą alokowalną.
x(:) = [5,6,7,8]
jest w porządku, gdy x
ma kształt prawej strony.
Składniki tablic tablic
type t
real y(5)
end type t
type(t) x(2)
Możemy również odnosić się do całych tablic, elementów tablicy i sekcji tablicy w bardziej skomplikowanych ustawieniach.
Z powyższego x
jest całą tablicą. Mamy też
x(1)%y ! A whole array
x(1)%y(1) ! An array element
x%y(1) ! An array section
x(1)%y(:) ! An array section
x([1,2]%y(1) ! An array section
x(1)%y(1:1) ! An array section
W takich przypadkach nie możemy mieć więcej niż jednej części referencji składającej się z tablicy o randze 1. Poniższe, na przykład, nie są dozwolone
x%y ! Both the x and y parts are arrays
x(1:1)%y(1:1) ! Recall that each part is still an array section
Operacje tablicowe
Ze względu na cele obliczeniowe operacje matematyczne na tablicach są w Fortranie proste.
Dodawanie i odejmowanie
Operacje na tablicach o tym samym kształcie i rozmiarze są bardzo podobne do algebry macierzy. Zamiast przeglądać wszystkie indeksy z pętlami, można napisać dodawanie (i odejmowanie):
real, dimension(2,3) :: A, B, C
real, dimension(5,6,3) :: D
A = 3. ! Assigning single value to the whole array
B = 5. ! Equivalent writing for assignment
C = A + B ! All elements of C now have value 8.
D = A + B ! Compiler will raise an error. The shapes and dimensions are not the same
Tablice z krojenia są również ważne:
integer :: i, j
real, dimension(3,2) :: Mat = 0.
real, dimension(3) :: Vec1 = 0., Vec2 = 0., Vec3 = 0.
i = 0
j = 0
do i = 1,3
do j = 1,2
Mat(i,j) = i+j
enddo
enddo
Vec1 = Mat(:,1)
Vec2 = Mat(:,2)
Vec3 = Mat(1:2,1) + Mat(2:3,2)
Funkcjonować
W ten sam sposób większość wewnętrznych funkcji może być domyślnie użytych przy założeniu, że operacja jest oparta na komponentach (choć nie jest to systematyczne):
real, dimension(2) :: A, B
A(1) = 6
A(2) = 44 ! Random values
B = sin(A) ! Identical to B(1) = sin(6), B(2) = sin(44).
Mnożenie i dzielenie
Należy zachować ostrożność przy produkcie i podziale: wewnętrzne operacje przy użyciu *
i /
symboli są elementarne:
real, dimension(2) :: A, B, C
A(1) = 2
A(2) = 4
B(1) = 1
B(2) = 3
C = A*B ! Returns C(1) = 2*1 and C(2) = 4*3
Nie należy tego mylić z operacjami macierzowymi (patrz poniżej).
Operacje na macierzach
Operacje na macierzach są procedurami wewnętrznymi. Na przykład iloczyn macierzy tablic z poprzedniej sekcji jest zapisany w następujący sposób:
real, dimension(2,1) :: A, B
real, dimension(1,1) :: C
A(1) = 2
A(2) = 4
B(1) = 1
B(2) = 3
C = matmul(transpose(A),B) ! Returns the scalar product of vectors A and B
Złożone operacje pozwalają na enkapsulację funkcji poprzez tworzenie tablic tymczasowych. Chociaż jest to dozwolone przez niektóre kompilatory i opcje kompilacji, nie jest to zalecane. Na przykład można zapisać produkt zawierający transpozycję macierzy:
real, dimension(3,3) :: A, B, C
A(:) = 4
B(:) = 5
C = matmul(transpose(A),matmul(B,matmul(A,transpose(B)))) ! Equivalent to A^t.B.A.B^T
Zaawansowane sekcje tablicowe: trojaczki indeksu dolnego i indeksy wektorowe
Jak wspomniano w innym przykładzie, do podzbioru elementów tablicy, zwanego sekcją tablicy, można się odwoływać. Z tego przykładu możemy mieć
real x(10)
x(:) = 0.
x(2:6) = 1.
x(3:4) = [3., 5.]
Sekcje tablicy mogą być jednak bardziej ogólne. Mogą przybierać formę trojaczków indeksu dolnego lub wektorowego.
Trojaczki indeksu dolnego
Potrójny indeks dolny ma postać [bound1]:[bound2][:stride]
. Na przykład
real x(10)
x(1:10) = ... ! Elements x(1), x(2), ..., x(10)
x(1:) = ... ! The omitted second bound is equivalent to the upper, same as above
x(:10) = ... ! The omitted first bound is equivalent to the lower, same as above
x(1:6:2) = ... ! Elements x(1), x(3), x(5)
x(5:1) = ... ! No elements: the lower bound is greater than the upper
x(5:1:-1) = ... ! Elements x(5), x(4), x(3), x(2), x(1)
x(::3) = ... ! Elements x(1), x(4), x(7), x(10), assuming omitted bounds
x(::-3) = ... ! No elements: the bounds are assumed with the first the lower, negative stride
Po określeniu kroku (który nie może być zerowy), sekwencja elementów zaczyna się od pierwszej określonej granicy. Jeśli krok jest dodatni (względnie ujemny), wybrane elementy postępują zgodnie z sekwencją zwiększaną (lub zmniejszaną) krokiem do momentu, aż ostatni element nie będzie większy (względnie mniejszy) niż druga granica. Jeśli krok zostanie pominięty, traktowany jest jako jeden.
Jeśli pierwsza granica jest większa niż druga granica, a krok jest dodatni, nie określono żadnych elementów. Jeśli pierwsza granica jest mniejsza niż druga granica, a krok jest ujemny, nie określono żadnych elementów.
Należy zauważyć, że x(10:1:-1)
to nie to samo co x(1:10:1)
mimo że każdy element x
pojawia się w obu przypadkach.
Indeksy wektorowe
Indeks dolny to tablica liczb całkowitych rangi 1. Oznacza to sekwencję elementów odpowiadającą wartościom tablicy.
real x(10)
integer i
x([1,6,4]) = ... ! Elements x(1), x(6), x(4)
x([(i,i=2,4)]) = ... ! Elements x(2), x(3) and x(4)
print*, x([2,5,2]) ! Elements x(2), x(5) and x(2)
Sekcja tablicowa z indeksem wektorowym jest ograniczona pod względem sposobu użycia:
- nie może być argumentem powiązanym z fikcyjnym argumentem zdefiniowanym w procedurze;
- może nie być celem w instrukcji przypisania wskaźnika;
- może nie być wewnętrznym plikiem w instrukcji przesyłania danych.
Ponadto taka sekcja tablicy może nie pojawić się w instrukcji, która obejmuje jej definicję, gdy ten sam element zostanie wybrany dwukrotnie. Z góry:
print*, x([2,5,2]) ! Elements x(2), x(5) and x(2) are printed
x([2,5,2]) = 1. ! Not permitted: x(2) appears twice in this definition
Sekcje tablicy wyższej rangi
real x(5,2)
print*, x(::2,2:1:-1) ! Elements x(1,2), x(3,2), x(5,2), x(1,1), x(3,1), x(5,1)