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:

  1. Cała tablica x ;
  2. Elementy tablicy, takie jak x(1) ;
  3. 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)


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow