728 x 90

, i

Julia – silna konkurencja języków takich jak Matlab, R czy Python cz. 2

Julia – silna konkurencja języków takich jak Matlab, R czy Python cz. 2

W pierwszej części poznaliśmy podstawowe polecenia oraz operatory używane w języku Juli. Teraz czas na bardziej skomplikowane struktury i oczywiście na tradycyjne „Hello World”. Uważamy, że po przeczytaniu tej części dostrzeżecie jeszcze więcej zalet tego innowacyjnego języka.

Julia – silna konkurencja języków takich jak Matlab, R czy Python cz. 2

Wstęp

W tej części zajmiemy się pierwszymi programami, w których będziemy używać zdobytych wcześniej wiadomości, a także poznamy takie rzeczy jak: funkcje, listy oraz wyjątki. Dla osób programujących są to pojęcia już znane, dla początkujących okażą się z pewnością łatwe do zrozumienia.

Hello world

Zacznijmy od tradycyjnego programu wyświetlającego napis „Hello world”. Jeżeli nie pracujemy w programie Juno możemy użyć konsoli. W tym celu wystarczy użyć zwykłego notatnika, osobiście jednak polecam Notepad++.

W dokumencie wpisujemy znaną już z innych języków komendę println(“hello world”). Plik zapisujemy z rozszerzeniem .jl.

Następnie otwieramy nasz najnowszy nabytek i komendą include wczytujemy napisany wcześniej kod. Pamiętajmy o wpisaniu rozszerzenia otwieranego pliku po jego nazwie.

Ze względu na wygodę kolejne części kodu pisane będą w programie Juno, dzięki czemu nie będziemy musieli używać konsoli.

Zmienne typu string

Zobaczmy, jak w tym języku zachowują się zmienne typu string. W tym celu napiszmy krótki kod, który na wiele sposobów pokazuje zasady ich wykorzystywania:

#tak wyglądają zmienne typu string
    s1="Kryptografia jest"
    s2="super"
    println("$s1 $s2")

#zmienne tego typu można łączyć w ten sposób:
    caly_zwrot = s1 * s2
    println("$caly_zwrot")

#oto inna metoda zapisu
    s3 = string("Beata", " stawia", " pizze")
    println(s3)

#możemy również zmieniać litery na duże(uppercase) i małe(lowercase)
    s3 = uppercase(s3)
    println(s3)

#tak wygląda zmienna typu char
    c1 = 'k'
#wyświetlenie kodów ASCI dla znaku
    println(c1, " kod ASCI: ", Int(c1))

#zmienne string mogą być traktowane jak listy:
    show(s3[1]); println()

    show(s3[14:18]); println()

  • Na początku wyświetliliśmy dwa oddzielne teksty za pomocą jednego polecenia println (jeżeli nie chcemy, by kolejne wyświetlenie odbywało się od nowej linii, możemy użyć funkcji print).
  • Kolejny napis „Kryptografia jestsuper” – najpierw do zmiennej przypisaliśmy połączone wartości dwóch zmiennych (s1 i s2) , jak widzimy efekt finalny jest bardzo podobny.
  • Wartym uwagi jest trzecie podejście, a zwłaszcza utworzenie zmiennej s3. Tworząc zmienną przypisujemy jej jeden tekst stworzony z trzech pierwotnych.
  • Kolejne funkcje będą bardzo przydatne w kryptologii. Na początku funkcja uppercase() – służy do zmieniania wszystkich liter zawartych jako argumenty funkcji na wielkie.
  • Czym jest tabela ASCII? Zna ją chyba każdy programista. Najprościej ujmując każda litera, znak, cyfra ma przypisaną wartość numeryczną. Aby odczytać tę wartość używamy funkcji rzutującej znak na zmienną typu całkowitoliczbowego.
  • Polecenia show służą do wyświetlenia wybranych liter z przedziału podanego przez programistę.
#Formatowanie Int za pomocą Int i float
    e_str1="2.718"
#Konwersja i pomnożenie razy 5
    e=float(e_str1)
    println(5e)
#Parsowanie do zmiennej całkowitoliczbowej float'a
    num_15=parse(Int,"15")
    println(3num_15)

#Konwersja za pomocą funkcji sprintf 
    e_str2=@sprintf("%0.3f",e)

#W Juli dostępne są także stałe matematyczne

  @printf "Pi o precyzji 3: %0.3f\n" float(pi)
  @printf "Zapis naukowy: %0.6e\n" 1000pi
  @printf "Notacja naukowa: " 1e10


Wywołanie programu:

Kilka prostych funkcji

Spróbujmy teraz napisać kilka prostych, podstawowych funkcji. Wszyscy chyba znają zasadę działania dodawania modulo. Aby utworzyć funkcje używamy następującego schematu:

function nazwa(arg1,arg2,…,argn)
     body
 end

Implementacja funkcji wraz z jej użyciem może wyglądać następująco:

dodawanie_modulo(a, b, m) = (a+b)%m
    a=5
    b=7
    m=13
    wynik = dodawanie_modulo(a, b, m)
      println("wynik dzialania $a + $b mod $m = $wynik")
    b+=b
    wynik = dodawanie_modulo(a, b, m)
      println("wynik dzialania $a + $b mod $m = $wynik")

Z uwagi na fakt, że funkcja dodawanie_modulo jest krótka, możemy również zapisać ją w następujący sposób:

dodawanie_modulo(a, b, m) = (a+b)%m

Operacje modulo opisaliśmy w artykule „Szyfr państwa białej flagi”, do którego serdecznie zapraszamy.

function rownanie_kwadratowe(a, b, c)
    println("Oblicznie miejsc zerowych funkcji kwadratowych")
    println("Funkcja w postaci $(a) x^2 + $(b) x + $(c)")
    delta=b^2 - 4*a*c

    if delta<0
        return "Brak miejsc zerowych w liczbach rzeczywistych"
    elseif delta>0
        return "Miejsca zerowe to $(((-1)*b+sqrt(delta))/(2*a)) oraz $(((-1)*b-sqrt(delta))/(2*a))"
    else
        return "Miejsce zerowe to:$(((-1)*b/(2*a)))"
    end

end

 print(rownanie_kwadratowe(2, 3, 4))

Wynik wywołania funkcji:

Teraz mamy do czynienia z matematyką licealną. Na podstawie zadanych argumentów funkcja oblicza współrzędne miejsc zerowych i zwraca wynik w postaci tekstu.  Jako pracę domową zachęcamy do wyjścia z przestrzeni liczb rzeczywistych i rozbudowanie funkcji o obsługę liczb zespolonych. W razie problemów – pomożemy ; ).

 

function podłogo_sufit(a::Float64)
    a::Int64=floor(a+0.5)
    return a end

#Funkcja podłogo-sufit zaokrągla podaną liczbę do najbliższej liczby Z print(podłogo_sufit(3.4))
    println()
    b=4
    a=convert(Float64,b)
    print(a)

Każdy programista używał wielokrotnie funkcji znanej jako rzutowanie. Jest to po prostu zmiana typów. Trzeba jednak pamiętać, że jest to operacja szczególnie niebezpieczna. Jeśli mamy liczbę zmiennoprzecinkową 3.5 i zamienimy ją na całkowitoliczbową to utracimy wartość po przecinku i dostaniemy 3. W programie przedstawiono konwersję za pomocą funkcji convert( Typ, zmienna )  oraz możliwość wymuszenia typu argumentu funkcji od użytkownika. Nasza funkcja podłogo_sufit przyjmuje tylko wartości zmiennoprzecinkowe. Gdzie jest używana? Np. w algorytmie LLL o którym wkrótce się dowiecie. A oto wyniki wywołania powyższego programu:

Listy (tablice) jednowymiarowe

Czasem zdarza się, że chcemy przetrzymać kilka wartości zmiennych. Jeśli z góry wiemy ile ich będzie, to nie ma problemu, możemy np. stworzyć 10 000 zmiennych i przypisać im odpowiednie wartości. Innym rozwiązaniem, znacznie bardziej eleganckim i rozwiązującym problem znajomości początkowej ilości zmiennych, są listy (w językach C++, C# , Java) znane jako tablicę. Są to najprościej mówiąc zbiory liczb, w których każda ma przypisany indeks.

Przykład: tablicę 9-cio elementową wypełnioną kolejnymi liczbami od 100 możemy sobie wyobrazić następująco:

UWAGA: INDEKSOWANIE TABLIC W JULII ZACZYNA SIĘ OD 1 !!!!!

A teraz kilka operacji na wspomnianych już listach:

  • Summary – zwraca typ obiektu
  • Repr – zwraca jego reprezentantów, w językach niższego stopnia występuje pętla for each
  • Lista =1:20 – uzupełnienie tablicy liczbami od 1 do 20, zastępuje pętle for inicjującą wartości w tablicy
  • Push! – wpisuje jako ostatni element listy wartość podaną przez programistę (nie da się wyjść poza indeks tablicy jak np. w C, ponieważ tablica sama się zwiększa w zależności od potrzeb)
function wypisz_wartosci_listy(lista)
     #summary zwraca typ obiektu, a repr jego reprezentantów
     println(summary(lista), ": ", repr(lista)"\n")
end

# tablice asocjacyjne (słowniki) mogą być deklarowane następująco:
    a1 = Dict(1=>"jeden", 2=>"dwa")
    wypisz_wartosci_listy(a1)

# dodawanie elementu do słownika wygląda następująco:
    a1[3]="trzy"
    wypisz_wartosci_listy(a1) #> Dict{Any,Any}: {2=>"dwa",3=>"trzy",1=>"jeden"}
# zwróć uwagę, w którym miejscu został dodany element

#funkcja haskey sprawdza, czy w podanym słowniku występuje szukany klucz
    println(haskey(a1,1))

# poniżej funkcja działająca na tej samej zasadzie
    println(1 in keys(a1)) #> true

# Wartości mogą być wypisywane na wiele sposobów, np:
    wypisz_wartosci_listy(values(a1))
    wypisz_wartosci_listy(collect(values(a1)))

Wynik wywołania funkcji:

Try, catch, czyli wyjście awaryjne

Czasem zdarzają się sytuacje wyjątkowe np. gdy zadziała system TAWS i piloci słyszą alarm Pull up nie czekają na rozbicie maszyny. Jest to sytuacja nadzwyczajna w której należy wykonać określoną procedurę aby się uratować. Tak samo w razie awarii program nie musi od razu zakończyć swojej pracy. Możemy zareagować na błąd i wykonywać program dalej. Problem ten jest podobnie rozwiązany w języku Java za pomocą klauzuli trycatch.  W pierwszej części znajduje się wykonywany kod, który może spowodować błąd, a w drugiej implementacja kodu który wykona się w przypadku wystąpienia wyjątku.

pusta_lista=[]
 # tak samo jak w innych językach do wykrywania błędow można użyc try, catch
 try
    push!(a,1)
 catch err
    showerror(STDOUT, err, backtrace());println()
 end
println("Beata wciąż nie postawiła nam pizzy :/")

Wynik skompilowania programu:

Zobaczmy co się stanie gdy celowo wywołamy wystąpienie wyjątku. Do nieistniejącej tablicy dodajemy element co jest oczywiście nie możliwie. Błąd jest przechwytywany przez klauzulę catch, a następnie wyświetlany na konsoli. Po wykonaniu tych operacji przechodzimy do wykonywania naszego programu i wypisania odpowiedniego tekstu.

Listy (tablice) wielowymiarowe

A co gdybyśmy chcieli napisać implementację gry w szachy? Plansza nie jest przecież jedno-, a dwuwymiarowa. Twórcy Juli też o tym pomyśleli. Zobaczmy jak to wygląda w praktyce.

function wypisz_wartosci_listy(lista)
   #summary zwraca typ obiektu, a repr jego reprezentantów
    println(summary(lista), ": ", repr(lista)"\n")
end

 m4 = [i+j+k for i=1:2, j=1:3, k=1:2] 
  wypisz_wartosci_listy(m4)

m1 = hcat(repeat([1,2],inner=[1],outer=[3*2]),
  repeat([1,2,3],inner=[2],outer=[2]),
  repeat([1,2,3,4],inner=[3],outer=[1]))
 
 wypisz_wartosci_listy(m1)

Wyniki wywołania funkcji:

Powyższy kod zawiera kilka ciekawych poleceń oraz implementację tablicy wielowymiarowej 2x3x2 zmiennych typu Int64.

  • Hcat() – funkcja ta ma na celu wygenerowanie tablicy wielowymiarowej.
  • Repeat – działanie tej funkcji zostało pokazane na konsoli, ale warto wspomnieć o niej chociaż jedno zdanie, ma ona za zadanie wypisać z powtórzeniami elementy, oraz w określony sposób.

Tablica asocjacyjna (ang. Dictionary)

Jest to powszechnie występująca w informatyce struktura abstrakcyjna. Przechowuje ona tak jak słownik unikatowy klucz oraz przypisaną do niego wartość. Pojawiają się one w większości języków programowania np. php, Java, C++.  Możemy na nich wykonywać kilka podstawowych operacji o których dowiecie się analizując poniższy kod.

function wypisz_wartosci_listy(lista)
  #summary zwraca typ obiektu, a repr jego reprezentantów
    println(summary(lista), ": ", repr(lista)"\n")
end

# tablice asocjacyjne(słowniki) mogą być deklarowane następująco:
  a1 = Dict(1=>"jeden", 2=>"dwa")
   wypisz_wartosci_listy(a1)

# dodawanie elementu do słownika wygląda następująco:
  a1[3]="trzy"
   wypisz_wartosci_listy(a1) #> Dict{Any,Any}: {2=>"dwa",3=>"trzy",1=>"jeden"}
# zwróć uwagę, w którym miejscu został dodany element

#funkcja haskey sprawdza, czy w podanym słowniku występuje szukany klucz
   println(haskey(a1,1))

# poniżej funkcja działająca na tej samej zasadzie
   println(1 in keys(a1)) #> true

# Wartości mogą być wypisywane na wiele sposobów, np:
   wypisz_wartosci_listy(values(a1))

wypisz_wartosci_listy(collect(values(a1)))
  • Deklaracja słownika jest bardzo prosta za pomocą polecenia Dict(X=>”Y”), oraz podania kluczy i wartości.
  • Za pomocą #> możemy dodać wartości do słownika.
  • haskey(X,Y) jest funkcją sprawdzającą czy istnieje już taki element w tablicy asocjacyjnej.

Wyniki wywołania funkcji:

 

 

Żródła obrazów: freeimages.com 

Implementacje zostały opracowane we własnym zakresie, a wartość merytoryczna została zaczerpnięta ze strony: https://learnxinyminutes.com/docs/julia/

Leave a Comment

Your email address will not be published. Required fields are marked with *

Cancel reply

Inne artykuły