wtorek, 23 stycznia 2018

Kompresja & dekompresja

Kompresja danychpolega na zmianie sposobu zapisu informacji tak, aby zmniejszyć redundancję i tym samym objętość zbioru. Innymi słowy chodzi o wyrażenie tego samego zestawu informacji, lecz za pomocą mniejszej liczby bitów.

Kompresja dzieli się na bezstratną – w której z postaci skompresowanej można odzyskać identyczną postać pierwotną oraz stratną – w której takie odzyskanie jest niemożliwe, jednak główne właściwości zostają zachowane. Np. jeśli kompresowany jest obrazek, nie widać znaczących różnic w stosunku do oryginału. Pomimo to może się już nie nadawać do dalszej przeróbki czy do wydruku, gdyż w tych zastosowaniach wymaga się zachowania innych właściwości.

Algorytmy kompresji dzieli się na algorytmy zastosowania ogólnego oraz algorytmy do danego typu danych. Z definicji nie istnieją algorytmy kompresji stratnej zastosowania ogólnego, ponieważ dla różnych typów danych konieczne jest zachowanie różnych właściwości. Na przykład kompresja dźwięku używa specjalnego modelu psychoakustycznego, który nie ma sensu w zastosowaniu do obrazu, poza bardzo ogólnymi przesłankami dotyczącymi sposobu postrzegania rzeczywistości przez człowieka.

Większość algorytmów bezstratnych to algorytmy zastosowania ogólnego oraz ich drobne przeróbki, dzięki którym lepiej działają z określonymi typami danych. Nawet drobne poprawki mogą znacząco polepszyć wyniki dla pewnych typów danych.

Algorytmy kompresji stratnej często jako ostatniej fazy używają kompresji bezstratnej. W takim przypadku poprzednie fazy mają za zadanie nie tyle kompresować, ile przygotować dane do łatwiejszej kompresji.

Dekompresja – proces odtworzenia oryginalnych danych na podstawie ich postaci skompresowanej, przy użyciu odpowiedniego do kompresji algorytmu dekompresji. Proces dekompresji jest działaniem przeciwnym do działania kompresji.

wtorek, 24 października 2017

Algorytm iteracyjny, iloczyn n liczb

Algorytm iteracyjny, iloczyn n liczb

1. Specyfikacja 

Zadanie: Oblicz iloczyn n liczb całkowitych.
Dane: n dowolnych liczb całkowitych, kolejno zapamiętywanych w zmiennej a.
Wynik: wartość iloczynu: iloczyn.

2. Schemat blokowy

3. Listing programu
#include <iostream>
using namespace std;
int main ()
{
    int i, a, iloczyn, n;
    cout << "Podaj ilosc liczb do przemnozenia ";
    cin >> n;
    iloczyn=1;
    for (i=0; i<n; i++)
    {
        cout << "Podaj liczbe nr " << i+1 << ": " ;
        cin >> a;
        iloczyn*=a;
    }
    cout << iloczyn;
    return 0;

}

Algorytm z pentlą zagnieżdżoną

Algorytm z pętlą zagnieżdżoną

1. Specyfikacja 

Zadanie: Wyprowadzenie na ekran prostokąta o bokach n, m narysowanego za pomocą znaków * (m-liczba znaków * w poziomie, n- liczba znaków * w pionie). Wnętrze prostokąta powinno być wypełnione znakami *.
Dane: liczby naturalne dodatnie, określające ilość znaków * w prostokącie o bokach m,n.
Wynik: prostokąt o wymiarach m x n, zbudowany ze znaków *.

2. Schemat blokowy 
3. Listing programu 
#include <iostream>
using namespace std;
int main ()
{
    int i, j, n, m;
    cout << "Wprowadz wartosc n: ";
    cin >> n;
    cout << "Wprowadz wartosc m: ";
    cin >> m;
    for (i=0; i<n; i++)
    {
        for(j=0; j<m; j++)
            cout << "*";
        cout << endl;
    }
    return 0;


}

Funkcje w języku C++

Funkcje w języku C++

1. Zasięg zmiennej określa zakres widoczności nazwy zmiennej w obrębie pliku.

Zasięg zmiennej to w programowaniu fragment programu (np. obszar lub blok kodu) z którym skojarzone są wartości lub wyrażenia (np. zmienne). Różne języki programowania posiadają różne rodzaje zasięgów widoczności.
Zasięgu najczęściej używa się do:
  • kontrolowania cyklu życia zmiennych
  • kontrolowania widoczności i dostępności zmiennych i stałych w obrębie programu
  • implementacji hermetyzacji
Zasięgi mogą zawierać:
  • deklaracje lub definicje identyfikatorów (np. zmiennych)
  • instrukcje lub wyrażenia definiujące wykonywalny algorytm lub jego część
  • inne, zagnieżdżone zasięgi
2. Ze względu na zasięg zmiennej rozróżniamy zmienne globalne i lokalne:

Zmienna globalna – zmienna istniejąca przez cały czas życia programu i widziana z wielu miejsc w programie.
Nadużywanie zmiennych globalnych może prowadzić do poważnych problemów, takich jak:
  • w przypadku programów wielowątkowych, zmienna taka może być modyfikowana przez dowolny wątek, co prowadzić może do nieokreśloności przy braku synchronizacji wątków.
  • jeśli funkcja używa zmiennej globalnej jako zmiennej pomocniczej, niemożliwe może być jej rekursywne wywołanie
  • zmienne globalne zaśmiecają przestrzeń nazw, w niektórych architekturach może to doprowadzić do przepełnienia stosu
  • na działanie danej części kodu może mieć wpływ kod zupełnie niezwiązany, o ile oba używają tej samej zmiennej globalnej i jeden z nich ją modyfikuje.
  • zmienne globalne mogą kolidować ze zmiennymi lokalnymi (te drugie przesłaniają zmienne globalne o ile posiadają identyczne nazwy).
Zmienna lokalna – zmienna zdefiniowana i dostępna wyłącznie w określonym bloku programu, tworzona w momencie wejścia do tego bloku oraz usuwana z pamięci w momencie wyjścia z danego bloku. Tym samym zasięg zmiennej lokalnej oraz czas jej życia pokrywają się i obejmują blok, w którym zmienna lokalna jest zdefiniowana. Zmienna lokalna ma więc określony, ograniczony zakres istnienia i dostępności. To w jakich blokach programowych można tworzyć zmienne lokalne definiuje składnia konkretnego języka programowania. Typowymi blokami, w których można w różnych językach programowania tworzyć zmienne lokalne, są moduły, podprogramy oraz w pewnych językach programowania także instrukcje blokowe (lub inne instrukcje strukturalne, np. pętla for w języku C++ i inne).

3. Zmienne globalne w języku C++ deklarujemy poza funkcjami.

Zmienne te są widoczne od miejsca deklaracji do końca pliku, również w funkcjach. 

Niezależnie od zmiennych globalnych można wewnątrz funkcji C++ zdeklarować zmiennie lokalne. 
Zmienne te będą widoczne w C++ w części programu od miejsca deklaracji do końca funkcji. W języku C++ zmienne lokalne mogą być również widoczne tylko w obrębie jednego bloku instrukcji {}.

Próba użycia zmiennej lokalnej w programie głównym spowoduje pojawienie się podczas kompilacji błędu niezdeklarowanej zmiennej. 

Zmiennym globalnym pamięć przydzielana jest na cały czas wykonywania programu, natomiast zmiennym lokalnym - tylko na czas działania procedury lub funkcji. 

4. Stosowanie zmiennej lokalnej.

void Usmiechy()
{
int k;
cin >>k;
if (k>0) for (i=0; i<20; i++) cout << ":-)";
else for (i=0; i<20; i++) cout << ":-(";
}

Zmienne globalne mogą zostać przesłonięte. Zdeklarowanie w procedurze lub funkcj zmiennej lokalnej o takiej samej nazwie jak zmienna globalna spowoduje przesłonięcie zmiennej globalnej, co oznacza, że używana będzie zmienna lokalna a nie globalna.

5. Przesyłanie zmiennej globalnej.

#include <iostream>
using namespace std;
int i;
void Usmiechy()
{
int i;
for (i=0; i<20; i++) cout << ":-)";
}
int main ()
{
i=10;
Usmiechy();
cout<<i;
return 0;
}

------------------------------------------------------------------

int main ()
{
for (i=0; i<20; i++) cout << ":-)";
cout << endl;
return 0;
}

wtorek, 10 października 2017

Programowanie

Modele programowania
Programowanie liniowe – klasa problemów programowania matematycznego, w której wszystkie warunki ograniczające oraz funkcja celu mają postać liniową. Warunki ograniczające mają postać:
Mamy zmaksymalizować lub zminimalizować funkcję celu, również liniową:
Zmienne xi są liczbami rzeczywistymi.
Nie zawsze taki problem ma jakiekolwiek rozwiązanie, np.:
Być może też żadne rozwiązanie nie jest optymalne, ponieważ potrafimy uzyskać dowolnie dużą wartość funkcji celu, np.:
Zmaksymalizuj  przy warunku
Programowanie liniowe znalazło szerokie zastosowanie w teorii decyzji, np. do optymalizacji planu produkcyjnego. Wiele problemów optymalizacyjnych znajduje rozwiązanie poprzez sprowadzenie ich do postaci problemu programowania liniowego.

Programowanie strukturalne – paradygmat programowania opierający się na podziale kodu źródłowego programu na procedury i hierarchicznie ułożone bloki z wykorzystaniem struktur kontrolnych w postaci instrukcji wyboru i pętli. Rozwijał się w opozycji do programowania wykorzystującego proste instrukcje warunkowe i skoki. Programowanie strukturalne zwiększa czytelność i ułatwia analizę programów, co stanowi znaczącą poprawę w stosunku do trudnego w utrzymaniu „spaghetti code” często wynikającego z użycia instrukcji goto.
Początki programowania strukturalnego przypadają na Lata 60. XX wieku, a ważnym głosem w dyskusji o programowaniu strukturalnym był list Edsgera Dijkstry Goto Statement considered harmful.
Język programowania zgodny z paradygmatem programowania strukturalnego nazywa się językiem strukturalnym.

Programowanie modularne (ang. modular programming) − paradygmat programowania zalecający stosowanie nadrzędności modułów w stosunku do procedur i bloków tworzących program. Moduł grupuje funkcjonalnie związane ze sobą dane oraz procedury i jest reprezentacją obiektu jednokrotnie występującego w programie. Programowanie takie wykorzystywane jest przez wyspecjalizowane języki programowania, np. Ada, Modula-2, Pascal, Fortran90.
Paradygmat programowania modularnego jest blisko związany z innymi paradygmatami, a mianowicie programowaniem strukturalnym i programowaniem zorientowanym obiektowo, gdzie jest często stosowany.

Programowanie obiektowe (ang. object-oriented programming) – paradygmat programowania, w którym programy definiuje się za pomocą obiektów – elementów łączących stan(czyli dane, nazywane najczęściej polami) i zachowanie (czyli procedury, tu: metody). Obiektowy program komputerowy wyrażony jest jako zbiór takich obiektów, komunikujących się pomiędzy sobą w celu wykonywania zadań.
Podejście to różni się od tradycyjnego programowania proceduralnego, gdzie dane i procedury nie są ze sobą bezpośrednio związane. Programowanie obiektowe ma ułatwić pisanie, konserwację i wielokrotne użycie programów lub ich fragmentów.
Największym atutem programowania, projektowania oraz analizy obiektowej jest zgodność takiego podejścia z rzeczywistością – mózg ludzki jest w naturalny sposób najlepiej przystosowany do takiego podejścia przy przetwarzaniu informacji.

Programowanie sterowane zdarzeniami (Programowanie zdarzeniowe) – metodologia tworzenia programów komputerowych, która określa sposób ich pisania z punktu widzenia procesu przekazywania sterowania między poszczególnymi modułami tej samej aplikacji. Programowanie sterowane zdarzeniami jest mocno powiązane ze środowiskami wieloprocesowymi (nie mylić z komputerami wieloprocesorowymi), z graficznymi środowiskami systemów operacyjnych oraz z programowaniem obiektowym.
Jest to paradygmat programowania, według którego program jest cały czas „bombardowany” zdarzeniami (events), na które musi odpowiedzieć, i zakładający, że przepływ sterowania w programie jest całkowicie niemożliwy do przewidzenia z góry.
Programowanie zdarzeniowe jest dominującym typem programowania GUI – zdarzenia to naciśnięcia myszy, klawiszy, żądania odświeżenia przez system okienkowy, różne zdarzenia sieciowe i inne.
Jest też używane przez wysoce wydajne serwery sieciowe – zdarzeniami są tu żądania połączenia, nadejście danych do odbioru, zwolnienie się miejsca w buforach wysyłania odbiorów, itd. W systemach uniksowych zwykle wszystkie połączenia (np. z plikami, sieciowe, z relacyjną bazą danych) mają charakter deskryptorów plików i na ich zbiorze jest wywoływana funkcja systemu operacyjnego select lub poll, która informuje na jakim deskryptorze wydarzyło się jakieś zdarzenie (zobacz artykuł: Wywołania systemowe Uniksa).
W programowaniu zdarzeniowym ważne jest żeby nie obsługiwać zbyt długo danego zdarzenia, bo blokuje się w ten sposób obsługę innych. W przypadku serwerów obniżyłoby to znacznie wydajność, w przypadku GUI program zbyt wolno odpowiadałby na akcje użytkownika. Można to osiągnąć za pomocą asynchronicznego I/O, wielowątkowości, rozbijania zdarzenia na pod zdarzenia i wielu innych mechanizmów.

Programowanie zstępujące i wstępujące
Programowanie zstępujące (projektowanie zstępujące, ang. top-down design) – rozwiązanie programistyczne polegające na zdefiniowaniu problemu ogólnego poprzez podzielenie na podproblemy, które są dzielone na jeszcze mniejsze podproblemy aż do rozwiązań oczywistych, łatwych do zapisania. Następnie złożenie z rozwiązań podproblemów niższego rzędu rozwiązań problemów wyższego rzędu aż do całkowitego rozwiązania problemu.
Programowanie wstępujące jest to długoletnią zasadą stylu programowania, że elementy funkcjonalne programu nie powinny być zbyt duże. Jeśli jakiś fragment programu urośnie ponad etap, w którym jest łatwo zrozumiały, staje się masą złożoności, która ukrywa błędy tak łatwo, jak duże miasto ukrywa zbiegów. Takie oprogramowanie będzie ciężkie do czytania, ciężkie do testowania i ciężkie do debugowania.

Zalety stosowania podprogramów

Podprogramy standardowe cechują się następującymi zaletami:
efektywność 
zwykle takie podprogramy, przygotowane przez profesjonalne firmy, są starannie opracowane, często w całości lub w istotnej części, w asemblerze bądź języku maszynowym i odpowiednio zoptymalizowane,
brak błędów 
wszechstronne testowanie skutkuje brakiem lub ograniczeniem błędów takich podprogramów,
standaryzacja 
pozwala na ujednolicenie oprogramowania, interfejsów użytkownika i ułatwia konserwację kodu,
ułatwienie i skrócenie kodowania 
uwalnia programistę od definiowania standardowych operacji,
programowanie hybrydowe 
często takie podprogramy są dostępne w kilku językach programowania i systemach.