Fortran/Zmienne
Czym jest i do czego służy zmienna?
edytujZmienną w programie komputerowym można rozumieć jako twór, który na 2 cechy:
- posiada unikalną nazwę (dzięki której można ją zidentyfikować)
- posiada wartość, czyli porcję informacji (niskopoziomowo jest to ciąg bitów).
typ zmiennej
edytujTyp zmiennej określa jej własności. Czy można porównać zmienną logiczną (prawda/ fałsz) ze zmienną tekstową? Czy liczba zmiennoprzecinkowa o podwójnej precyzji przechowa dobrze wartość 1.003? To zależy od typu zmiennej
Na typ zmiennej składają się
- Zbiór wartości, jakie może przechować dany typ
- Zbiór relacji, jakie może tworzyć dany typ z innymi typami
- Zbiór operacji, jakie można wykonać na danym typie
Zmienna w pamięci komputera to ciąg bitów. Program musi wiedzieć, w jaki sposób ją traktować. Inaczej działa się na liczbach całkowitych a inaczej jest na liczbach zmiennoprzecinkowych.
Typy dzielą się na proste i złożone. Typ prosty przechowuje jedną wartość (np. jedna wartość całkowita).
Typ złożony określa zmienną, która może zawierać ma w sobie inne zmienne. W języku FORTAN77 taką wartością jest np. tablica. Jedna tablica może być ciągiem np. 100 wartości zmiennoprzecinkowych.
W nowszych standardach języka Fortran wprowadzono bardziej zaawansowane wersje typów złożonych. Do problematyki typów złożonych należy podchodzić z rozsądkiem. Zbyt "wybujałe" struktury danych zaczynają sprawiać problemy z ich zrozumieniem. Przeglądanie dużych, zaawansowanych struktur danych jest często mniej wydajne (pojawiają się dyskusje o wyższości FORTRAN77 nad Pythonem albo C++). Te problemy wynikają często z faktu, że w FORTRAN77 mamy proste tablice z jednym typem danych (np. tablica 1000 liczb jednego typu), natomiast w "nowoczesnym języku obiektowym" możliwe jest utworzenie np. tablicy 1000 obiektów. Każdy obiekt jest "autonomiczną" strukturą danych zawierającą zarówno dane jak i algorytmy działające na tych danych. Wtedy można zaprogramować "obliczanie", kiedy każde przetworzenie "nowoczesnego obiektu" wiąże się z wywołaniem metody dla danego obiektu. Każde wywołanie podprogramu wiąże się zwykle ze stratą ponad 100 taktów procesora. Rezultatem niepotrzebnego wywoływania tego samego algorytmu 1000 razy jest program obiektowy działający np. 100 razy wolniej od prymitywnego FORTRANA77.
Przykład. Można utworzyć tablicę 1000 liczb. chcemy podnieść je po kolei do kwadratu i zapisać w drugiej tablicy. W Fortranie 77 wystarczy jeden podprogram z pętlą. Przeglądamy całą tablicę, wykonujemy na każdej liczbie działanie i zapisujemy do drugiej tablicy. W wersji obiektowej możemy pożeglować do granic wyobraźni. Mamy 2 tablice obiektów. Jeden obiekt wykonuje metodę, aby wydać przechowywaną wartość. Drugi obiekt wykonuje działanie aby zapisać w sobie wczytaną wartość (uwzględniając podniesienie do potęgi).
Jednym z pierwszych zastosowań języków takich jak FORTRAN77 było robienie tabel funkcji. Tablice wystarczały do tego celu. Jedna tablica mogła przechowywać wartość dziedziny, druga - przeciwdziedziny. Coś, jakby x i f(x).
W takim duchu można traktować "starszy" standard FORTRAN77.
pamięć operacyjna w języku Fortran
edytujJęzyk Fortran jest językiem kompilowanym bezpośrednio do kodu maszynowego.
Standard FORTRAN77 nie przewiduje dynamicznego alokowania pamięci. Pamięć jest alokowana na stosie (np tablica statyczna).
Nowsze standardy języka Fortran posiadają możliwość dynamicznej alokacji pamięci na stercie. Zarządzanie pamięcią zależy od użytkownika. Programista może spróbować zaalokować pamięć na stercie. Jeżeli operacja się uda, wówczas programista wykonuje jakieś działania na niej, potem ją zwalnia i ok.
Język Fortran nie posiada mechanizmów odśmiecania, kontrolujących wykorzystywanie pamięci (w przeciwieństwie np. do języka Java). Spowodowane jest to tym, że obliczenia numeryczne zazwyczaj wymagają działania np. na dość dużych strukturach danych (pod względem rozmiaru), natomiast niezbyt złożonych pod względem różnorodności cech. Przykładem jest obliczanie rozkładu pola elektrostatycznego. Potencjał jest przechowywany w dość dużej tablicy (z punktu widzenia komputerów starszych generacji), ale zawierająca zmienne jednego typu.
Język FORTAN77 był tworzony w latach 50-tych, kiedy wyzwaniem było nawet określanie wzoru funkcji bez konieczności "ręcznego manipulowania" układami liczącymi ówczesnych "mózgów elektronowych". Pamięć była liczona w kilobajtach. Bajt nie zawsze miał 8 bitów.
Dla porównania, język Java powstawał na początki lat 90-tych XX wieku. Mechanizm "odśmiecania" miał polegać na tym, że programista jedynie tworzy nowe obiekty, natomiast program co jakiś czas zatrzyma swoje działanie i zaczyna "analizować", czy dany obiekt jest wykorzystywany, czy też nie. Piszący te słowa nie czuje się na siłach być sędzią. Należy jedynie zwrócić uwagę, że język Java jest niejednokrotnie stosowany do tworzenia "rosochatych" struktur obiektowych uruchamianych na wydajnych serwerach, natomiast osoby wykonujące obliczenia numeryczne stosują "tradycyjne" narzędzia, które robią to, co im się rozkarze.
Pamięć jest to nic innego, jak tylko ciąg bitów, które zależnie od interpretacji, mogą dla programu stanowić liczbę całkowitą, znak (jedną literkę), łańcuch (kilka literek) lub liczbę rzeczywistą (w notacji dziesiętnej z kropką). Aby wymusić interpretację ciągu bitów o określonej długości używamy tzw. typów zmiennej. Typ definiuje zwykle też długość zmiennej. Dzięki użyciu typów program wie, że np. zmienna x przechowuje jakąś liczbę całkowitą a zmienna y przechowuje liczbę rzeczywistą. Aby korzystać ze zmiennych musimy je uprzednio zadeklarować.
W nowszych standardach języka Fortran wykonuje się to w następujący sposób (według normy Fortran95):
typ_zmiennej :: nazwa_zmiennej
lub (według standardu FORTRAN77) :
typ_zmiennej nazwa_zmiennej
nazwy zmiennych
edytujNazwa zmiennej musi jak najwierniej opisywać obiektu rzeczywistego, który ta zmienna opisuje.
Zalecane nazwy zmiennych zależą od typu zmiennej.
- zmienne liczbowej - można jej nadać formę orzekającą np. LICZBA_ELEKTRONOW, ZASIEG_RZUTU_KAMIENIA, PREDKOSC_SAMOLOTU_X.
- zmienne logiczne - można np. DANE_SA_POPRAWNE, KONTYNUUJ_OBLICZENIA
Każda zmienna musi mieć dobrze opisane swoje znaczenie. Najlepiej na początku programu. Pozwala to uniknąć późniejszego zgadywania znaczenia zmiennej.
Każda zmienna powinna być używana zgodnie ze swoim przeznaczeniem. Wykorzystywanie jednej zmiennej przez różne elementy programu nie związane ze sobą powoduje problemy ze zrozumieniem działania programu.
Typy zmiennej
edytujTyp zmiennej może odnosić się do różnego rodzaju danych, które mają być przechowywane w zmiennej.
Liczby
edytujTyp zmiennej | Opis | Przykładowe wartości |
---|---|---|
integer | liczba całkowita | 15, -6500, 200000000 |
real | liczba zmiennoprzecinkowa pojedynczej precyzji | 3.1415, -5.5, .7e3, 12.5E-5 |
double precision | liczba zmiennoprzecinkowa podwójnej precyzji | 3.1415D0, -5.5D0, .7d3, 12.5D-5 |
complex | liczby zespolone (kombinacja części rzeczywistej i urojonej) | (3.1415, -5.5), (1.4, 7.1E4) |
Zmienne liczbowe mogą być podawane w różnych systemach liczbowych. Domyślnie przyjmowany jest dziesiętny, jednak, aby kompilator wiedział, że używasz innego systemu, przyjmuje się następujące założenia:
Zapis | System |
---|---|
Z"liczba" lub Z'liczba' | szesnastkowy |
O"liczba" lub O'liczba' | ósemkowy |
B"liczba" lub B'liczba' | binarny |
Język Fortran dopuszcza także definiowanie przez programistę rozmiaru zmiennej. Uzyskuje się to poprzez dodanie w deklaracji zmiennej następującej konstrukcji:
real*4 nazwa_zmiennej
lub
real nazwa_zmiennej -domyślny typ
lub
real(kind=4)::nazwa_zmiennej
oznacza 4-bajtową liczbę rzeczywistą. Natomiast, aby uzyskać typ podwójnej precyzji używamy konstrukcji:
real*8 nazwa_zmiennej.
lub
real(kind=8)::nazwa_zmiennej
w niektórych kompilatorach możemy uzyskać poczwórną precyzje.
real(kind=16)::nazwa_zmiennej
Wartości logiczne
edytujDo przechowywania wartości logicznych także przeznaczono specjalny typ danych.
Typ | Opis | Możliwe wartości |
---|---|---|
logical | Przechowywanie wartości logicznej | .TRUE. lub .FALSE. |
Znaki i łańcuchy
edytujPrzechowywanie pojedynczych znaków odbywa się przy pomocy typu CHARACTER. Natomiast deklarowanie łańcucha polega na dodaniu * oraz długości łańcucha (w znakach). Oznacza to, że aby przechować np. nazwę "pl.Wikibooks" musimy napisać tak:
character*12 :: nazwa="pl.Wikibooks"
print *, nazwa
Uwagi, dotyczące długości poszczególnych typów danych:
- dla typu integer możliwe jest zaalokowanie 1, 2, 4 lub 8 bajtów
- dla typu real odpowiednio 4 lub 8
- dla typu Complex 8 lub 16
- dla typu character nie ma ograniczeń długości
Stałe
edytujJęzyk Fortran umożliwia także deklarację zmiennych, których zawartości nie da się zmieniać. Są to tzw. stałe. Deklaruje się je podobnie do zmiennych, z tą jednak różnicą, że przy nazwie typu dodajemy słowo parameter. Dla standardu Fortran 95 wygląda to następująco:
typ, parameter :: nazwa = wartość
Natomiast według Fortran 77 wygląda to tak:
typ nazwa parameter (nazwa=wartość)
Uwaga: kompilator języka Fortran nie zasygnalizuje błędu, jeśli stałej w kodzie programu przypiszesz inną wartość! Np.
integer, parameter :: p = 3 print *, "p=",p parameter p = 9 print *, "p=",p
Tablice
edytujCzasami zdarza się, że potrzebujemy przechować więcej niż jedną wartość danego typu (np. real). Język Fortran umożliwia nam zestawianie kilku zmiennych w tzw. tablicę. Definiuje się ją następująco:
typ zmienna(wymiar)
gdzie wymiar oznacza ilość zmiennych tego samego rodzaju. W tym przypadku będzie to tablica jednowymiarowa. Możemy jednak używać tablic wielowymiarowych, np. 2x2:
real tablica(2,2)
Nie należy jednak definiować tablicy o zbyt dużej ilości wymiarów - niesie to ze sobą duże zużycie pamięci.
W przeciwieństwie do innych języków programowania (np. do C, ale nie do Pascala), Fortran numeruje elementy tablicy od 1!! (Chyba, że ustalimy inaczej) |
Sposoby deklaracji tablic
edytujW przeciwieństwie do np. języka C, język Fortran umożliwia programiście deklarację tablicy na wiele różnych sposobów. Oto niektóre z nich:
Sposób pierwszy:
real tablica(10)
Sposób drugi:
real tablica dimension tablica(10)
Sposób trzeci:
integer index parameter (index=10) real tablica(index)
Sposób czwarty:
real tablica(0:9)
W specyfikacji F95, deklaracja różni się tylko tym, że używany jest dwukropek (::).
Modyfikowanie zawartości tablicy
edytujAby zmodyfikować jakiś element tablicy, musimy znać jego położenie. Do tego celu służy tzw. indeks. Aby zmodyfikować pierwszy i drugi element tablicy piszemy:
tablica(1) = 0.4 tablica(2) = 0.3
Odczyt zawartości jakiegoś elementu tablicy dokonuje się w analogiczny sposób:
print *, "Tablica[1]=", tablica(1)