Pokazywanie postów oznaczonych etykietą time. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą time. Pokaż wszystkie posty

środa, 27 stycznia 2016

Aliasy w GIT

Aliasy w GIT to fantastyczne narzędzie upraszczające pracę.
Parę aliasów stworzyłem i chciałbym się z Tobą nimi podzielić.

Kod z aliasami jest zamieszczony na github'ie.
Żeby skorzystać z tych aliasów to będziesz musiał zmodyfikować configurację.
git config --global --edit
Dobrze jest zmienić edytor w git. Ja korzystam z atoma. Jak też masz atoma to możesz go używać pisząc taką komendę:
git config --global core.editor "atom --wait"
Przykład pobrany stąd.
Jeżeli chcesz, żeby w czasie otwartego programu atom można było pisać w konsoli to usuń parametr wait.
Na Windowsie mam inny tool. Edytor zawsze możemy zmienić przez modyfikację pliku
[core]
editor = \"c:/program files (x86)/Notepad++/notepad++.exe\" -multiInst -nosession
W pliku gitconfig dodaj ścieżkę do pliku z aliasami.
[include]
    path = /PathToRepos/git_config/gitalias
Jeżeli chcesz sprawdzić czy ścieżka jest skonfigurowana to napisz w konsoli:
git config --global include.path
Pod ścieżką /PathToRepos/git_config/ masz plik gitalias, który zawiera wszystkie aliasy.
Możesz sciągnąć kod źródłowy aliasów za pomocą gita uruchamiająć w katalogu PathToRepos taką komendę:
git clone https://github.com/arekbee/git_config

Jak zapiszesz ten plik to możesz zobaczyć jakie aliasy są zdefiniowane poprzez komendę aliasesd:
git aliases
Aby zobaczyć definicje aliasów wystarczy dopisać literkę d do poprzedniego wywołania
git aliasesd


Poniżej zamieszczam krótki opis niektórych komend. Poniższe komendy będę przedstawiał na sklonowanym repo z github.com/fsharp/fsharp.
Szybkie dodanie i spuszowanie zmian. ACP to skrót od Add, Commit i Push.
git acp "message"
Ściągnięcie kodu źródłowego, ale bez folderu .git
git download https://github.com/arekbee/git_config.git
Pobranie autorów kodu z informacjami o liczbie commitów:
git authors | head -10
Kiedy będziesz refaktoryzował kod i nie będziesz wiedział od czego zacząć to może powinieneś poszukać najczęściej modyfikowane pliki.
git churn
Jeżeli chcesz usunąć wszystkie niezatwierdzone zmiany i niewersjonowane pliki to napisz:
git clean-all
Szukanie nazwy plików, które zawierają dany ciąg znaków
git find-file ".exe"
Wyświetla historię commitów
git hist
Jeżeli napiszesz git histd to uzyskasz historię commitów z wiadomościami.
Wyświetl ścieżkę w której repo. zostało stworzone.
git root
Jeżeli chcesz wyświetlić jakieś poliki, które nie zostaną dodane do repo (bo wzorzec w .gitignore jest spełniony) to wywołaj poniższą komendę:
git ls-ignore
Dodać submodule (git externalne repo.)
git siur
Pokaż wszystkie branche które nie zostały zmergowane:
git unmerged-branches 
Stwórz plik z grafem commitów
git graphviz  -n10 > graph.dot
graphviz\dot.exe -Tpng graph.dot -o graph.png​
Tutaj jeszcze będę musiał popracować. Jak na razie wygląda to tak:

Mam nadzieję, że aliasy się przydadzą. Ja najczęściej korzystam z acp.

piątek, 18 grudnia 2015

Benchmarki z webowych frameworków

Miesiąc temu wyszła 11 runda porównań frameworków webowych pod względem szybkości działania. Teraz już wiem dlaczego (dla celów wydajnościowych) wybiera się java nad c# oraz dlaczego niektóre projekty mają w back-end jvm, a od strony klienckiej jest .NET.

Wyselekcjonowałem tylko te frameworki, które zostały napisane w java i c#.
Wyniki są następujące:


Możesz sam wyselekcjonować te informacje jakie Cię interesują wchodząc na ten link.
Zastanawia się dlaczego Microsoft nie ma na celu zrobienia oddzielnej super szybkiej wersji aspnet'a dla celów komercyjnych. Pewnie wyrzuci się masę funkcjonalności związanymi z bezpieczeństwem, ale trudno.

Zawsze mi mówiono, że najlepsze frameworki powstają w środowiskach otwartych, tam gdzie za daną technologią stoją wielkie firmy - np. java i Oracle, go i google, c++ i producenci gier, objective-c i Apple, php i wikipedia, js i wszystkie strony :)

sobota, 9 maja 2015

For loop dla msbuild

Jak będziesz chciał uruchomić kilka razy dany proces to możesz wykorzystać polecenia for. Ja tak muszę z budowaniem projektów w .NETcie. Musze 2 razy uruchomić msbuild'a. Niektóre projekty nie maja referencji do innych projektów w solucji, ale do zbudowanych bibliotek w specjalnym folderze. Problem też może być jak jedno budowanie projektu potrzebuje dużo czasu (dajmy na to 25 minut) i w każdym momencie może wystąpić błąd.

Polecenie do dwukrotnego budowania jest poniżej:
for /L %n in (1,1,2) do ( msbuild myProject.sln /m )​

Takie proste, a tak upraszcza życie :)

niedziela, 13 kwietnia 2014

Pamiętaj o aktualizacji pomocy w PS

Dobrą praktyką przy pracy z PowerShellu jest aktualizacja pomocy. Niestety nie zawsze o tym pamiętam :) i dobrze jest dodanie sobie zdarzenia które będzie aktualizowało zadanie. Na samym początku tworzymy trigger, który będzie uruchamiany w piątki wieczorem jak komputer nie będziesz pracował przy komputerze oraz update będzie uruchamiany nawet jak notebook będzie działał na baterie (StartIfOnBattery).
$trigger = New-JobTrigger -Weekly -At "8:00 PM" -DaysOfWeek Friday 
$scheduledOption = New-ScheduledJobOption –StartIfIdle -StartIfOnBattery -RequireNetwork 
Skrypt, który wykonuje update wygląda następująco:
$updateScript = {Update-Help -Module * -Force}
Aby zarejestrować zdarzenie wystarczy wykonać poniższe polecenie
Register-ScheduledJob -Name UpdatePowerShellHelp -Trigger $trigger -ScheduledJobOption $scheduledOption -ScriptBlock $updateScript 
Aby zobaczyć wynik należy przejść do okna z harmonogramem zadań:
start "Taskschd.msc"


piątek, 21 marca 2014

Czas generowania zmiennej losowej w PS

Ostatnio sprawdzałem szybkość działania polecenia do generowania zmiennych losowych z przedziału (0,1).
Sprawdzimy wywołanie zmiennych losowych 1000 razy i zapisanie tych zmiennych do tablicy:

$count =1000
$num1= @()
$num2= @()


Poniżej kod do sprawdzenia obiektu z klasy random:
$objRandom = new-object random
$measure1 = Measure-Command -Expression {
            for ($i =0; $i -lt $count; $i++)
            {
              $num1 += $objRandom.NextDouble()
            }
}

I w przypadku polecenia Get-Random (alias random):
$measure2 = Measure-Command -Expression {
            for ($i =0; $i -lt $count; $i++)
            {
               $num2 += (random)/[Int32]::MaxValue 
            }
}


Wynik czasu działania jednego z kilku wywołań:

$measure1: 
TotalSeconds      : 0,3785933
TotalMilliseconds : 378,5933

$measure2:
TotalSeconds      : 56,7377659
TotalMilliseconds : 56737,7659
Wynik mnie nie zaskoczył. Spowolnienie może mieć kilka powodów:
- korzystanie z aliasu
- polecenia PS są wolniejsze niż wywołania obiektów .NET
- przy każdym wywołanieu polecenia radnom, tworzy się obiekt, a w pierwszym przypadku obiekt już jest zainicjalizowany
- dodatkowa operacja dzielenie liczby losowej przez maksymalną liczbę int

czwartek, 20 marca 2014

Wielkość folderów w PS

Zastanawiałeś się jak można sprawdzić wielkość folderów w podkatalogach? Poniżej jest kod w PS, który wyświetla wielkość folderów w podkatalogach.

function Show-SpaceUsage
{
    [CmdLetBinding()]
    param(
        [Parameter(Mandatory=$true, Position=0)]  
        [ValidateScript({Test-Path $_ })]
        [string]$path,

        [decimal]$parentSize=0,

        [ValidateNotNullOrEmpty()]
        [string]$format = "N2"
    )
    $size = (Get-ChildItem $path -Recurse | ?{$_.PSIsContainer -eq $false} | measure -property length -sum).sum
   
    $parentPercentage =1
    if($parentSize -ne 0)
    {
       $parentPercentage = $size / $parentSize  
    }

    $item = gi $path
    new-object PSObject | 
            Add-Member -PassThru -MemberType NoteProperty -Name  Path  -Value $item.FullName |
            Add-Member -PassThru -MemberType NoteProperty -Name  Name  -Value $item.Name |
            Add-Member -PassThru -MemberType NoteProperty -Name  GB  -Value ("{0:$format}" -f ($size / 1GB)) |
            Add-Member -PassThru -MemberType NoteProperty -Name  MB  -Value ("{0:$format}" -f ($size / 1MB)) |
            Add-Member -PassThru -MemberType NoteProperty -Name  KB  -Value ("{0:$format}" -f ($size / 1KB)) |
            Add-Member -PassThru -MemberType NoteProperty -Name  "Percentage of Parent" -Value ("{0:$format}" -f $parentPercentage)

    $dirs =  Get-ChildItem $path | ?{$_.PSIsContainer -eq $True} | sort Name
    $dirs | %{
        Show-SpaceUsage -path $_.FullName -parentSize  $size
        Write-verbose ""
    }
}

Wyniki są sformatowane do tabeli:
Show-SpaceUsage -path "." -Verbose | Format-Table

Oczywiście można wyniki wyeksportować do csv i tam już posortować po największych folderach:
Show-SpaceUsage -path "." | Export-Csv -path "result.csv" -Delimiter ';' -NoTypeInformation -Encoding ASCII 

piątek, 28 lutego 2014

Generowanie start.bat dla projektu w VS

Czy kiedykolwiek musiałeś uruchomić aplikację z linii poleceń, która miała tak dużo linijek z argumentami, że nie mieściła się w oknie cmd? Ja miałe taką przyjemność i ten post jest właśnie o tym jak rozwiązać taki problem. Problem można rozwiązać za pomocą programu wsadowego (na ogół nazywam go start.bat). W nim zawarte jest polecenie startujące aplikację z argumentami. Aby debugować taką aplikację z poziomy VS to należy dodać parametry do właściwości programu. Poniżej są przedstawione 2 argumenty:
Napisałem skrypt w PS, aby wygenerować start.bat, który będzie mógł być wystartowany z tymi argumentami:
function New-StartBat
{
    param(
        [string] $csprojFilePath,
        [string] $outputDir = "." 
    )

    $userFileExtension = ".user"
    $startBatFileName = "start.bat"

    if(!(test-path $csprojFilePath))
    {
        throw "Wrong path to csproj file: $csprojFilePath"
    }

    [xml]$csprojContent = gc $csprojFilePath 
    [string]$outputType = ([string]$csprojContent.Project.PropertyGroup.OutputType)
               .Trim();

    if( -not($outputType -match  "Exe"))
    {
        throw "Output type is not exe"
    } 

    $assemblyName = ([string]$csprojContent.Project.PropertyGroup.AssemblyName)
                  .Trim()
    $startbarContent = "start /B $assemblyName.$outputType"
    $userFile = $csprojFilePath + $userFileExtension

    if(!(test-path $userFile))
    {
        Write-host "No user file for $csprojFilePath"
        $outputConditionStartBat  = join-path  $outputDir  $startBatFileName
        Write-Host "Genereting start.bat. Output is  $outputConditionStartBat"
        
        $startbarContent |
             out-file  $outputConditionStartBat  -Encoding ascii
    }
    else 
    {
        #region For each condition in user file
        [xml]$userFileContent = gc $userFile
        $userCondition = $userFileContent.Project.PropertyGroup.Condition

        $csProjConditions = $csprojContent.Project.PropertyGroup.Condition
        foreach($csprojCondition in $csProjConditions)
        {
            if($csprojCondition -eq $null)
            {
                continue;
            }

            [string]$conditionString =  ([string]$csprojCondition)
                                  .Trim()


            $indexOfequals = $conditionString.LastIndexOf("==")+2;
            if($indexOfequals -gt 2)
            {
                $conditionSimpleString = $conditionString
                     .Substring($indexOfequals)
                     .Trim()
                     .Replace("'","")
                     .Replace("|","_")

                if($contains =  $userCondition -contains $conditionString)
                {
                   $propertyGroup =  $userFileContent.Project.PropertyGroup | 
                                ?{$_.Condition -eq $conditionString }

                   $startArguments = $propertyGroup.StartArguments

                   $startBatContentWithArgs = $startbarContent+ " " + $startArguments 
           
                   $outputConditionStartBat  = join-path  $outputDir  ($conditionSimpleString + "_" +$startBatFileName) 

                   Write-Host "Genereting start.bat for $conditionSimpleString. Output file is $outputConditionStartBat"

                   $startBatContentWithArgs |
                    out-file  $outputConditionStartBat  -Encoding ascii
                }
            }

        }
        #endregion
    }
}
Dla różnej konfiguracji (Platform Configuration) możemy mieć różne parametry. Wygenerowany start.bat możemy uzyskać poprzez wywołanie polecenia:
New-StartBat -csprojFilePath "SuperProjectName.csproj" -outputDir ".\bin\Debug"

wtorek, 25 lutego 2014

Symbol Newtona w PowerShell

Chciałem poćwiczyć z symbolem Newtona, więc postanowiłem napisać skrypt w PS, aby porównać te sposoby uzyskiwania współczynnika dwumianowego.
Oczywiście do symbolu Newtona będziemy potrzebowali funkcję zwracającą wartość silni.
function Get-Factorial([int]$n)
{
    if($n -lt 1) {
        return 1
    }
    $facttorialRec = Get-Factorial($n -1)
    return ($n * $facttorialRec )
}
Jak na razie funkcja oblicza silnie rekurencyjnie (ale mam w planach dodać jeszcze silnie obliczoną w sposób iteracyjnie).

Mamy też funkcję obliczającą symbol Newtona za pomocą rekurencji:
function Get-BinomialCoefficientRec([int]$n, [int]$k)
{
    if($k -lt 0 -OR $k -gt $n)
        {return 0}

    if($k -eq 0 -OR $k -eq $n -OR $n -lt 1)
        {return 1} 

    $diff = $n - $k
    if($k -gt $diff)
    {
        $k = $diff
    }
    
    $binomial1 = Get-BinomialCoefficientRec -n ($n-1) -k $k
    $binomial2 = Get-BinomialCoefficientRec -n ($n-1) -k ($k-1)
    return $binomial1 + $binomial2
}


Oraz funkcję korzystającą z tożsamości algebraicznej:
function Get-BinomialCoefficientIteratively([int]$n, [int]$k)
{
    if ($k -lt 0 -or  $k -gt $n)
    {return 0}
 
    if($k -eq  0 -or  $k -eq  $n)
    { return 1}

    $diff = $n - $k
    if ($k -gt $diff)
    {  $k = $diff }
    
    $prod = 1
    for($i=1; $i -le $k; $i++)
    {
        $prod = $prod * (  ($n - $i + 1) / $i  )    
    }

    return $prod
}

Możemy wyliczyć symbol Newtona na ze wzoru Sterlinga. Wzór ten stosuje się dla bardzo dużych liczb, gdyż błędy względne są małe.
function Get-StirlingApproximation([int]$n)
{

    $numDivE = $n / [math]::E
    $const = [math]::Sqrt(2.0 * $n * [math]::PI)
    $result = $const * ([math]::Pow(($numDivE) ,$n))   
    if($result -eq 0)
        {return 1}
    return $result
}


Główna funkcja, która agreguje funkcje zliczające współczynnik dwumianowy jest przedstawiona poniżej:

function Get-BinomialCoefficient
{
    param(
    [ValidateSet('factorial','recursive', 'multiplicative', 'stirling'  )]
    [string]$arg='factorial',

    [Parameter(Mandatory=$true, Position=0)]  
    [int]$n,

    [Parameter(Mandatory=$true, Position=1)]  
    [int]$k
    )

    if($arg -eq 'factorial')
    {
         $upperFractal = Get-Factorial($n) 
         $lowerFractalK = Get-Factorial ($k) 
         $lowerFractalNK=  Get-Factorial($n- $k)
         return $upperFractal  / ($lowerFractalK * $lowerFractalNK)
    }
    elseif($arg -eq 'stirling')
    {
        $aproxN = Get-StirlingApproximation($n)
        $aproxK = Get-StirlingApproximation ($k)
        $aproxNK = Get-StirlingApproximation($n- $k)
        return  $aproxN/ ( $aproxK  *$aproxNK )
    }
    elseif($arg -eq 'recursive')
    {
        return Get-BinomialCoefficientRec -n $n -k $k
    }
    elseif($arg -eq 'multiplicative')
    {
        return Get-BinomialCoefficientIteratively -n $n -k $k
    }

    throw 'Wrong argument in parameter $arg'
}


A funkcja do pomiaru wygląda następująco:
function Measure-BinomialCoefficient([int]$to)
{
    $Nenum = 1..$to
    $Nenum | %{
        $n = $_
        $Kenum = 1..$n 
        $Kenum | %{
           $k = $_
           $factorialMeasure =         
(Invoke-Command  {  Get-BinomialCoefficient -arg factorial -n $n -k $k       })

           $multiplicativeMeasure =    
(Invoke-Command  {  Get-BinomialCoefficient -arg multiplicative -n $n -k $k  })

           $recursiveMeasure =         
(Invoke-Command  {  Get-BinomialCoefficient -arg recursive -n $n -k $k       })

           $stirlingMeasure =          
(Invoke-Command  {  Get-BinomialCoefficient -arg stirling -n $n -k $k        })


            return new-object PSObject | 
                
Add-Member -PassThru -MemberType NoteProperty 
-Name  n  -Value $n |
               
Add-Member -PassThru -MemberType NoteProperty 
-Name  k  -Value $k |
                
Add-Member -PassThru -MemberType NoteProperty 
-Name  factorial  -Value $factorialMeasure |
                
Add-Member -PassThru -MemberType NoteProperty 
-Name  multiplicative  -Value $multiplicativeMeasure |
                
Add-Member -PassThru -MemberType NoteProperty 
-Name  recursive  -Value $recursiveMeasure |
                
Add-Member -PassThru -MemberType NoteProperty 
-Name  stirling  -Value $stirlingMeasure
        }
    }
}

Wyniki tych wywołań są przedstawione poniżej. Co prawda wzór Stirling nie daje dokładnej wartości, ale jestem pod wrażeniem przybliżenia wartości symbolu Newtona.



Aby uzyskać czasy działania algorytmów to wystarczy zamienić słowa Invoke na Measure oraz dodać TotalMilliseconds - pomiary są w milisekundach.
           $factorialMeasure =         
(Measure-Command  {  Get-BinomialCoefficient -arg factorial -n $n -k $k       }).TotalMilliseconds

           $multiplicativeMeasure =    
(Measure-Command  {  Get-BinomialCoefficient -arg multiplicative -n $n -k $k  }).TotalMilliseconds

           $recursiveMeasure =         
(Measure-Command  {  Get-BinomialCoefficient -arg recursive -n $n -k $k       }).TotalMilliseconds

           $stirlingMeasure =          
(Measure-Command  {  Get-BinomialCoefficient -arg stirling -n $n -k $k        }).TotalMilliseconds

A poniżej wykres przedstawiający czasy działania algorytmów (dla różnych n i k):



Gdybyśmy ograniczyli ilość danych poprzez wprowadzenie parametru k jako połowa parametru n oraz przedstawili dane na wykresie w skali logarytmicznej to mamy taki wykres:

Co dla mnie jest dziwne, to czasy obliczeń symbolu Newtona za pomocą wzoru Sterlinga oraz dla iteracyjnego sposób wyliczenia się zmniejszają :)
Takie rzeczy to tylko w PS.


sobota, 15 lutego 2014

Skróty klawiszowe do VS

Jak wiadomo skróty klawiszowe są bardzo przydatne bo polepszają naszą produktywność, więc dobrze jest mieć skróty dopasowane do własnych potrzeb. Z indywidualnymi skrótami klawiszowymi jest jeden problem - osoba, która nie zna twoich skrótów może mieć problemy z obsługą środowiska programistycznego, już nie mówiąc o takim dziwnym tworze jak Ping-Pong Pair Programming. Ja mam skróty dopasowane do siebie i osoby na moim komputerze nie wiedzą jak ja mogę w ogóle kodować :)

Poniżej jest tabelka ze skrótami. Wywołanie polecenia składa się z kombinacji skrótów. Pierwszy skrót oznacza grupę, a drugi skrót już konkretne polecenie. Jeżeli chcesz odpalić polecenie debugowania to korzystasz z grupy RUN (CTRL + R) i polecenie Debug.Start (CTRL + D). Jeżeli bez chcesz uruchomić bez debagowania to pod tej samej grupie jest polecenie Debug.StartWithoutDebugging (CTRL + SHIFT + D).
Niektóre skróty już coś oznaczają (CTRL + F czy CTRL + A), więc musiałem dołożyć dodatkowy klawisz.



Plik z ustawieniami importu w Visual Studio jest poniżej:


Moje skróty ewoluują, Wcześniej miałem skrót do zen codingu, czy do GhostDoc'a. Czasami skróty są zależne od projektu.

środa, 2 października 2013

Porównanie C5 z System.Collections.Generic

Jestem po lektorze książki ".NET 4.0 Generics" napisanej przez Sudipta Mukherjee (wcześniej na jego stronie można było ściągnąć całą książkę). Najbardziej cenie tą książkę za przedstawienie wyników szybkości działania różnych typów kolekcji. Autor porównuje typy, które znajdują się w bibliotece C5 oraz w System.Collections.Generic. O bibliotece C5 już wcześniej pisałem. Chciałbym przedstawić zdjęcia z wynikami z tej książki.

Eksperyment nr 1:
Ile czasu potrzeba, aby sprawdzić czy element w liście istnieje.

Eksperyment nr 2:
Ile czasu potrzeba, aby znaleźć pierwsze wystąpienie elementu w liście.


Eksperyment nr 3:
Ile czasu potrzeba, aby znaleźć ostatnio występujący element w liście


Eksperyment nr 4:
Ile czasu potrzeba, aby dodać element w losowym miejscu w liście


Eksperyment nr 5:
Ile czasu potrzeba, aby usunąć pojedynczy element w losowym miejscu w liście


Eksperyment nr 6:
Ile czasu potrzeba, aby uzyskać dostęp do elementu w kolekcji asocjacyjnej (Dictionary, SortedDictionary, C5.HashDictionary, C5.TreeDictionary)


Eksperyment nr 7:
Ile czasu potrzeba, aby znaleźć unie dwóch zbiorów


Eksperyment nr 8:
Ile czasu potrzeba, aby sprawdzić czy jeden zbiór zawiera się w drugim zbiorze


Kod źródłowy dla tych testów można było pobrać stąd. Mam nadzieję, że Sudipta reaktywuje swoją stronę.


wtorek, 12 marca 2013

Generowanie hasła w PowerShell

Wydaje mi się, że jedno z najczęściej wykonywanych zadań administratorów to jest generowanie nowego hasła dla użytkownika :) Ten post przedstawi Ci w jakie sposoby będziesz mógł wygenerować hasło.

Możesz skorzystać z funkcji Get-Random. Ta funkcja będzie losowała znaki ASCII. Poniżej jest kod:
$length = 8 #długość znaków hasła
$arr = 
33..33 + # znak: !
35..46 + # znaki: #$%&'()*+,-. 
48..57 + # znaki: 0123456789
64..90 + # znaki: @A-Z
97..122  # znaki: a-z 

$result= Get-Random  -count $length -input $arr | %{ [char]$_} 
[string] -join  $result  

Innym sposobem na wygenerowanie hasła jest użycie genreator GUID. Masz ograniczenie do 32 znaków, ale wydaje mi się że nie ma takiego szaleńca, który by wygenerował hasło dla użytkownika składające się z ponad 32 znaków :)
$length = 8
$guid = [Guid]::NewGuid().ToString() -replace "-", "" 
$guid.Substring(0,$length)

Jeżeli chciałbyś skorzystać z dedykowanej klasy do generowania hasła z .NET to możesz użyć Membership.GeneratePassword.
$length = 8
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
[System.Web.Security.Membership]::GeneratePassword($length,0)

Ale pomimo tych wszystkich udogodnień i tak chciałem stworzyć swoją własną funkcję do generowania hasła. Poniżej jest skrypt:
function Generate-Password 
{
  Param(
     [int] $length=8,
     [int] $numberOfNonAlphanumericCharacters=0
)

$allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
if ($numberOfNonAlphanumericCharacters -gt 0)
{
     $allowedChars += "-&@#%!*$?_";
}
$rnd = new-object System.Random    
$passwordChars = @()
for ($i = 0; $i -lt $length; $i++) 
{ 
  $rndIndex = $rnd.Next(0, $allowedChars.Length)
  $passwordChars += @( $allowedChars[$rndIndex] ) 
}
return [string] -join $passwordChars
}

środa, 6 marca 2013

Zmiana rozmiaru zdjęć za pomocą PowerShell

Czy masz może bardzo dużo zdjęć w jednym katalogu, musisz zmienić rozmiar tych zdjęć i za każdym razem uruchamiasz program graficzny, aby zmienić rozmiar zdjęcia??
Ja akurat tak miałem wiele razy :)
Jeśli coś powtarzasz wielokrotnie to postaraj się zautomatyzować tą czynność. Poniżej jest skrypt, który zmienia rozmiar zdjęcia.
function Resize-Image {
[CmdletBinding()]
Param(
     [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] 
     [System.io.FileInfo] $filepath,
     [int] $width=100,
     [int] $height=100,
     [string]$prefix="rs_"
)

PROCESS{
        $filePathFullName = $filepath.FullName
        if( Test-Path $filePathFullName)
        {
            $destName = $prefix+$filepath.name
            $destPath = Join-Path -path  $filepath.DirectoryName $destName
            
            import-bitmap $filePathFullName | resize-bitmap -Width $width -Height $height | export-bitmap  -Path $destPath 
            Write-Host "Resizing into $destPath"
                   
        }
        else {
            Write-Host "Path not found."
            }
        }
}
Przykład użycia jest przedstawiony poniżej:
gci -filter *.bmp |  Resize-Image 

Ten skrypt może u ciebie nie działać, bo prawdopodobnie nie masz PowerShell Community Extensions. Skrypt korzysta z poleceń import-bitmap,resize-bitmap i export-bitmap, które znajdują się w PSCX. Aby zainstalować PSCX, to wystarczy pobrać paczkę ze strony internetowej. Rozpakować do jednej z lokalizacji zawartej w zmiennej $Env:PSModulePath. A na końcu wywołać poniższy skrypt:
Import-Module Pscx -arg ~\PSCX\Pscx.UserPreferences.ps1
Get-Module

Mam nadzieję, że skrypt się przyda :)

wtorek, 5 marca 2013

Problemy z produktywnością


Znasz może ten żart:

Są rodzaje seksu: więzienny, studencki, przedszkolny i filozoficzny.
Więzienny: Jest gdzie, ale nie ma z kim,
Studencki: Jest z kim, ale nie ma gdzie.
Przedszkolny: Jest gdzie, jest z kim, ale nie ma czym.
Filozoficzny: Jest gdzie, jest z kim, ale czy jest sens...?



Wydaje mi się, że tak sam podział może być z problemami produktywności.

Przedszkolny: nie ma zadań, nie wiadomo jak, nie ma narzędzi.
Studencki: są zadania, nie ma wiedzy(jeszcze nie), są narzędzia.
Więzienny: są zadania, jest wiedza, nie ma narzędzi.
Filozoficzny: są zadania, jest wiedza, są narzędzia, ale jaki to ma sens?



Jeżeli jesteś typem przedszkolaka to nie musisz dbać o produktywność bo nie masz zadań. I z tego też powodu wszyscy ci zazdroszczą.

Jeżeli jesteś typem studenta to już powinieneś dbać o produktywność bo są zadania. Pomimo tego, że masz dostęp do narzędzi nie wykorzystujesz je. Mi bardzo brakuje dostępu do DreamSparka. Stamtąd można było pobrać bardzo dużą ilość programów za darmo. Doceniłem to dopiero po studiach.

Jeżeli jesteś typem więźnia to masz zadania i wiedzę, które mogą zwiększyć produktywność. Ale nie masz wymaganych narzędzi. Z taką sytuacją może się spotkać, gdy pracujesz w firmie, gdzie nie ma dostępu do potrzebnych narzędzi.

Jeżeli jesteś filozofem. to masz zadania do zrobienia, potrzebną wiedzę, wymagane narzędzia, ale nie obchodzi cię czy jesteś produktywny. Masz swoje przyzwyczajenia, które nie chcesz zmieniać.


piątek, 14 grudnia 2012

Dobre filmy

Czy kiedykolwiek zdarzyło ci się, że oglądałeś film w kinie, na który polecił ci kolega lub trailer był fajny i po parunastu minutach (nie liczę czasu z reklamami przed filmem) okazało się, że jest to kompletny badziew. Ja wtedy siedzę spokojnie i mówię do sobie, że „już zapłaciłem i poświeciłem czas na dojazd do kino, to jeszcze tą godzinę wytrzymam”. Jeżeli miałeś taką sytuacje jak ja, to może ci pomóc mechanizmu zaimplementowany na portalu filmweb. Teraz oglądam te dobre filmy, wygenerowane z rekomendacji.



Ale jakie są dobre, a jakie słabe filmy? Każda osoba ma swój własny gust filmów. Mechanizmem do wyliczania scoringu filmu nazywa się Gustomierz. Korzysta z wielu zmiennych, takich jak gatunek, głosy innych użytkowników czy twórcy filmu. Model do wyliczenia najlepszych filmów działa na bazie algorytmu K-najbliższych sąsiadów.
I pamiętaj. Szanuj swój czas jaki poświęcasz na oglądanie filmów.

piątek, 7 grudnia 2012

Rozpakowanie gz w PowerShell

Ostatnio miałem problem z rozpakowaniem dużej ilości spakowanych plików, wiec musiałem napisać skrypt, który będzie mógł rozpakować wszystkie pliki do wyznaczonego katalogu. Z pomocą przyszedł mi Power Shell, a skrypt wyglądał następująco:
$files = gci -Filter *.zip 
$dirInto = (Get-Location).Path
foreach ($file in $files) {
Write-Host "Processing $file"
$shell_app=new-object -com shell.application
$fileFullName = $file.FullName

$zip_file = $shell_app.NameSpace($fileFullName)
$destinationFolder = $shell_app.NameSpace($dirInto) 
$destinationFolder.CopyHere($zip_file.Items())
}
Rozwiązanie znalazłem na blogu msdn.
Wszystko ok, ale jak chciałem rozpakować pliki gz to już miałem problem. Zabrałem się za przerobienie kodu. Nie chciałem, aby rozwiązanie było uzależnione od jakieś aplikacji, na przykład od PowerShell Community Extensions
Na samym początku napisałem kod w c#, który posłużył mi za podkładke,w którym to korzystam z GZipStream.
using (FileStream fsRead =
 new FileStream(filePath, 
               FileMode.Open, 
               FileAccess.Read,
               FileShare.Read))
            {
                string fileName = 
Path.GetFileNameWithoutExtension(filePath);

                using (FileStream outFile = File.Create(Path.Combine(dirname,fileName)))

                using (GZipStream zipStream= 
new GZipStream(fsRead, 
CompressionMode.Decompress))

                    zipStream.CopyTo(outFile); //.NET 4.0
            }

Później zacząłem przerabiać ten kod na skrypt w PS.
function Unzip-Gzip
{
    param
    (
        [String]$inFile,
        [String]$outDir
    )
 
    if (! (Test-Path $inFile))
    {
        "Input file $inFile does not exist."
        exit 1
    }
 
    if (! (Test-Path $outDir))
    {
        "Output direcotri $outDir does not exist."
        exit 1
    }
   

    $inputFile = New-Object System.IO.FileStream $inFile, 
([IO.FileMode]::Open), 
([IO.FileAccess]::Read), 
([IO.FileShare]::Read)


     try{
        $newFileName = 
[System.IO.Path]::GetFileNameWithoutExtension($inFile)

        $newFilePath = 
[System.IO.Path]::Combine($outDir, $newFileName)  

        $outputDir = 
[System.IO.File]::Create($newFilePath)

        try{
            $inputFileGzip = 
New-Object System.IO.Compression.GZipStream $inputFile, ([System.IO.Compression.CompressionMode]::Decompress)

            try{
                $inputFileGzip.CopyTo($outputDir)
            }finally{
                $inputFileGzip.Close()
            }
        }finally{
            $outputDir.Close()
        }
    }finally{
        $inputFile.Close()
    }
}
Niestety nie mogłem wywołać metody CopyTo, gdyż ta metoda pojawiła się dopiero w .NET 4.0 i nie występuje w PS 2.0. Zamiast tej metody stworzyłem funkcje, która mogła przekopiować Stream.
function Copy-Stream 
{
    param
    (
        [System.IO.Stream]$inputStream,
        [System.IO.Stream]$outputStream
    )

 $bufferSize = 1024
 $buffer = New-Object byte[] $bufferSize
 
 while($true)
 {
    $byteCount = $inputStream.Read($buffer, 0, $bufferSize) 
    if ($byteCount -le 0)
    {
        break;
    }
    $outputStream.Write($buffer,0, $byteCount)
 } 
}

Ostatecznie funkcja Unzip-Gzip wyglada tak:
function Unzip-Gzip
{
    param
    (
        [String]$inFile,
        [String]$outDir
    )
 
    if (! (Test-Path $inFile))
    {
        "Input file $inFile does not exist."
        exit 1
    }
 
    if (! (Test-Path $outDir))
    {
        "Output direcotri $outDir does not exist."
        exit 1
    }
   


    $inputFile = New-Object System.IO.FileStream $inFile,
 ([IO.FileMode]::Open), 
([IO.FileAccess]::Read), 
([IO.FileShare]::Read)

     try{
        $newFileName =
[System.IO.Path]::GetFileNameWithoutExtension($inFile)

        $newFilePath = 
[System.IO.Path]::Combine($outDir, $newFileName) 
 
        $outputDir = 
[System.IO.File]::Create($newFilePath)
        try{
            $inputFileGzip = 
New-Object System.IO.Compression.GZipStream $inputFile, ([System.IO.Compression.CompressionMode]::Decompress)

            try{
#$inputFileGzip.CopyTo($outputDir)
#Not in POWERSHELL 2.0
                Copy-Stream  $inputFileGzip $outputDir
            }finally{
                $inputFileGzip.Close()
            }
        }finally{
            $outputDir.Close()
        }
    }finally{
        $inputFile.Close()
    }
}
A skrypt do rozpakowania plików gz wygląda następująco:
$files = gci -Filter *.zip 
$dirInto = (Get-Location).Path
foreach ($file in $files) {
Write-Host "Processing $file"
$shell_app=new-object -com shell.application
$fileFullName = $file.FullName

Unzip-Gzip $fileFullName  $dirInto
}


czwartek, 6 grudnia 2012

Any w listach

Czasami w kodzie widzę coś takiego:
 IEnumerable<int> numbers= new List<int> { 1,2,3,11,22,33};

 if (numbers.Count() > 0)
 { 
   //code... 
 }

Nic wielkiego jeżeli mamy listę do tyś. elementów, ale co się stanie, gdy lista składa się z dużo większej liczby elementów lub elementy są jako 'ciężkie obiekty'. Metoda Count() ma liniową złożoność obliczeniową. Poniższa tabela przedstawia ilość elementów i czas działania metody Count w ms. Oczywiście na innym komputerze czas działania metody będzie inny.

CountCount time
1000
1,0000
10,0000
100,0001
1,000,00013
10,000,000130
100,000,0001332
1,000,000,00013243


Zastanawiam, się dlaczego programiści nie używają metody Any(), która ma złożoność O(1). Metoda ta sprawdza czy jest przynajmniej jeden element w liście. A co jeżeli będziemy chcieli sprawdzić czy w liście jest przynajmniej n-elementów? Ja wpadłem na parę rozwiązań.

if (numbers.Count() >= indexOf)
{
//count
}

if (numbers
.Select((x, i) => new { x, i })
.Any(arg => arg.i >= indexOf))
{
//select&any
}


if (numbers
.Skip(indexOf)
.Any())
{
//skip&any
}

if (numbers
.ElementAtOrDefault(indexOf+ 1) != default(int))
 {
 //elementAt
}

if (numbers
.Take(hasIndexes)
.Count() == indexOf)
{
//take&count
}


Zmienna indexOf określa ile elementów chcielibyśmy, aby było w liście. Metoda ElementAtOrDefault mogła by spełniać warunek zadania tylko wtedy, gdyby lista nie zawierała domyślnej wartości elementu. Poniżej przedstawiam wyniki czasu działania dla tych sposobów. Czas jest liczony w ms.

IndexOfCountSelect&AnySkip&AnyElementAtTake&Count
1282652101
10277690000
100279160000
1,000286040000
10,000284230000
100,000286053112
1,000,0002854132121421
10,000,00028408321128137205
100,000,000285293222130213902065
1,000,000,0002858332342132681378920489

Wykres w skali liniowej i logarytmicznej:



Wniosek jest taki, że najlepiej przeskoczyć potrzebną liczbę elementów w liście i sprawdzić czy jest jakiś element (skip&any).

Gdyby lista byłaby IList<T> to można jeszcze zastosować indexOf lub właściwość Count:

if (numbers
.IndexOf(hasIndexes) != -1)
{

}

Jeżeli znasz inne sposoby to opisz je w komentarzu. Jestem ciekaw co można jeszcze zrobić.

poniedziałek, 28 maja 2012

Zrozumieć LinkedList

Klasa LinkedList jest w .NET Base Class Library od bardzo dawna (od wersji 2.0) i bardzo rzadko jest używana. Zawsze była dla mnie pewną tajemnicą, więc postanowiłem zrobić parę testów na tej klasie. Ogólny sposób działania linked listy można poczytać na stronie wikipedii. Poniżej przedstawiam w punktach krótką charakterystykę:

1) LinkedList występuje tylko w postaci generycznej (LinkedList<T>).

2) LinkedList nie jest "listą" - to znaczy, że nie implementuje interfejsu IList. Interfejsy z których implementuje LinkedList to:
  • ICollection<T>, ICollection
  • IEnumerable<T>, IEnumerable
  • ISerializable, IDeserializationCallback

Dla uproszczenia słownictwa przyjmujemy, że LinkedList<T> i List<T> będziemy nazywać listą.

3) Metody AddFirst i AddLast określają kolejność zapisywanych obiektów. Możemy w prosty sposób dodać obiekt na końcu listy jak i na początku
NP:
var linkedList = new LinkedList<int>();  
//tworzy LinkedList

            linkedList.AddFirst(1);    
//   1 

            linkedList.AddFirst(2);    
//   2, 1

            linkedList.AddFirst(3);    
//   3, 2, 1


            linkedList.AddLast(4);     
//   3, 2, 1, 4 

            linkedList.AddLast(5);     
//   3, 2, 1, 4, 5

            linkedList.AddLast(6);     
//   3, 2, 1, 4, 5, 6




4) Możemy dodać element do wyznaczonego węzła
var linkedList = new LinkedList<int>();            
//tworzy LinkedList

            var objOne= linkedList.AddFirst(1);                
// 1

            var objTwo =   linkedList.AddAfter(objOne, 2);     
// 1, 2

            var objThree = linkedList.AddBefore(objTwo, 3);    
// 1, 3, 2

            var objFour =  linkedList.AddAfter(objThree, 4);   
// 1, 3, 4, 2

            var objFive =  linkedList.AddAfter(objFour, 5);    
// 1, 3, 4, 5, 2



5) LinkedList nie stosuje się we wszystkich zagadnieniach. Poniżej przedstawiam wyniki czasu działa różnych operacji na LinkedList i List. Wyniki są przedstawiane w milisekundach dla tysiąca, 10 tysięcy, 100 tysięcy oraz miliona elementów w listach. Na początku implementacja:
            var list = new List<int>();
            var linkedList = new LinkedList<int>();
            Stopwatch watchLinkedList = new Stopwatch();
            Stopwatch watchList = new Stopwatch();

5a) Dodawanie elementu na końcu listy.
            watchList.Start();
            for (int i = 0; i < counts; i++)
            {
                list.Add(i);
            }
            watchList.Stop();

            watchLinkedList.Start();
            for (int i = 0; i < counts; i++)
            {
                linkedList.AddLast(i);
            }
            watchLinkedList.Stop();


Wykres jest przedstawiony w skali liniowej. Poniżej tabela z wynikami:

Add Last
 LinkedListList
1,00000
10,00000
100,00091
1,000,00010613
10,000,0002770256

Bardzo dokładnie widać, że czas dodawania elementu na koniec listy dla LinkedList jest większy niż dla List.

5b) Dodawanie elementu na początku listy
            watchList.Start();
            for (int i = 0; i < counts; i++)
            {
                list.Insert(0,i);
            }
            watchList.Stop();

            watchLinkedList.Start();
            for (int i = 0; i < counts; i++)
            {
                linkedList.AddFirst(i);
            }
            watchLinkedList.Stop();


Add First
 LinkedListList
1,00000
10,000025
100,00082347
1,000,00097274540

Wykres jest przedstawiony w skali logarytmicznej. Tutaj dokładnie widać, że czas dla List jest dużo większy od LinkedList. Dla 100 tys. jest około 300 razy większy, a dla miliona elementów jest z 3 000 razy większy.

Sprawdźmy co się stanie, gdy porównamy dla LinkedList metodę AddFirst (dodawanie elementu na początek listy) z metodą AddLast (dodawanie elementu na koniec listy). Okazuje się, że czasy dla tych operacji są bardzo zbliżone.


Add FirstAdd Last
1,00000
10,00000
100,00089
1,000,00097106
10,000,00027752770


5c) Usuwanie podanego elementu z gotowej listy (za pomocą metody Remove(int))

Remove
 LinkedListList
1,00000
10,000024
100,00022370
1,000,00030283608

Czas dla List<T> przy operacji usunięcia elementów jest bardzo duży. Wiąże się to z koniecznością "przebudowania" listy (klasa List<T> jest zaimplementowania za pomocą Array).

5d) Sortujemy elementy. Do tego zastosujemy metodę rozszerzającą OrderBy

OrderBy
 LinkedListList
1,00004
10,00011
100,0001819
1,000,000212233
10,000,00033353092

Czas poświęcony na sortowanie listy dla obu klas jest bardzo podobny.

5e) Dodawanie elementu w sam środek listy
Kod dla List:
for (int i = 0 ; i < counts ; i++)
{
  int center = (int)
        Math.Floor( (double)list.Count / 2 );
  list.Insert( center, i );
}

Kod dla LinkedList:
bool addBefore = false;
LinkedListNode<int> centerNode = linkedList.AddFirst(0); ;
for (int i = 1; i < counts; i++)
{
if (addBefore)
{
  centerNode = linkedList.AddBefore( centerNode, i );
  addBefore = false;
}
else
{
  centerNode = linkedList.AddAfter( centerNode, i );
  addBefore = true;
}
}


Add Inner
 LinkedListList
1,00010
10,000015
100,00091467
1,000,000155148823
10,000,000273619992188

Wykres jest przedstawiony w skali logarytmicznej. Operacja na 10 milionach elementach w LinkedList jest podobnie czasochłonna co operacja na 100 tysiącach dla List. W tym eksperymencie ewidentnie widać, że lepiej jest zastosować LinkedList.

Poniżej jest porównanie 3 operacji. Dodawanie elementu na początek listy, w środek i na koniec list. Wyniki są prawie identyczne.
Add FirstAdd InnerAdd Last
1,000010
10,000000
100,000899
1,000,00097155106
10,000,000277527362770


5f) Przechodzenie po liście. Dla uproszenie sprawdzę wykonania operacji foreach oraz znajdę liczbę maksymalną.

ForeachMax
 LinkedListListLinkedLIstList
1,0000000
10,0000000
100,0001011
1,000,000951511
10,000,0009666165118

Wnioski: LinkedList<T> bardzo dobrze sprawuje się przy modyfikacji (dodawanie i usuwanie) obiektów w liście, natomiast List<T> dobrze sprawdza się przy dodawaniu elementu na końcu listy. Z racja, że LinkedList<T> nie ma indeksu to przechodzenie po liście jest kosztowniejsze niż dla List<T>.


piątek, 11 maja 2012

Skyrim Videos

Ostatnimi czasy zająłem się grą Skyrim. Nie będę opisywał tej czasochłonnej gry, ale chciałbym zwrócić uwagę na pewne zjawisko związane z tą grą. Chodzi o filmiki instruktarzowe. Skyrim jest grą nieliniową, można wchodzić w interakcję z postaciami, każde zdarzenie wpływa na dalszą rozgrywkę, zadania w grze można wykonać na wiele sposobów, świat w grze jest bardzo duży, a naszą postać można dowolnie rozwijać. Te cechy spowodowały, że bardzo dużo graczy zamieszcza filmiki z prostymi wskazówkami.



Aby przybliżyć ci tą grę przedstawiam ci pierwszy filmik z pierwszymi 10 minutami gry. Spolszczenie Skyrim można uznać za bardzo dobre. Dobra obsada postaci.



Filmiki instruktarzowe pomagają, aby w łatwy sposób przejść grę. Aby przejść grę musisz wypełniać misje.Jedna z najciekawszych misji do wykonania jest przedstawiona poniżej:



A tutaj jest przedstawiony filmik jak uzyskać 81 poziom postaci (maksymalny poziom):



W tym filmiki jest przedstawiony sposób w jaki można zdobyć nieskończenie wiele pieniędzy:



Powstają też filmiki w jaki sposób można zdobyć wybrany przedmiot:



Świat Skyrim jest pełny niezliczonej liczby (może ktoś policzył) misji. Niektóre zadania są ukryte. Poniższy filmik przedstawia taką misje:



Filmik przedstawia jak można być niewidzialny:



Skyrim nie jest wolny od dziur. Błędy w grze można wykorzystać między innymi w uzyskaniu ponadprzeciętnych umiejętności:





Popularność wśród filmików instruktarzowych zdobywają speedrunery, w których to filmikach przedstawiona jest możliwość bardzo szybkiego przejścia całej gry. Skyrim można przejść w 2 godziny i 50 minut wykonując tylko zadania główne oraz unikając walki z przeciwnikami:



Teraz przestałem grać. Może w przyszłości będę kontynuował walkę ze smokami. Zapisałem grę na ogólnodostępnej przestrzeni. Moja postać ma 80 poziom oraz 20 punktów do wykorzystania na dowolne cechy w umiejętnościach. Poniżej save mojej postaci:



A gdybyś chciał poczytać więcej o Skyrim to polecam wiki's tutaj lub tutaj.

czwartek, 3 maja 2012

Algorytmy sortowania

Aby poćwiczyć algorytmikę napisałem parę algorytmów sortowania i sprawdziłem czasy ich działania. Porównałem 12 algorytmów sortowania (m.in. Bubble Sort, Cocktail, Counting Sort, Insert Sort, Merge Sort, ShellSort, Stooge Sort). Kod z algorytmami sortowania można pobrać z github.com/arekbee/SortEngines. Podczas pisania nie kierowałem się złożonością obliczeniową tych algorytmów, ale byłem ciekaw w jakim czasie mogę posortować tablicę z liczbami.

Jak wiadomo, czas sortowania zależny jest od danych. Dane do posortowania składały się z liczb naturalnych. Każdy z algorytmów został sprawdzony pod 6-ma rożnymi tablicami danych. Pierwszy typ danych składał się z liczb losowych (random). Dla każdego algorytmu były te same dane. Drugi typ składał się z tablicy, w której pierwsza liczba była maksymalną liczbą, a pozostałe elementy były już posortowane w sposób rosnący (increasing). Następnym typem danych był modyfikacją poprzedniej tablicy poprzez wprowadzenie powtórzeń wartości tej tablicy (increasing-repeated). Ilość powtórzeń wynosiła wartość pierwiastka z ilości elementów w tablicy (jeżeli elementów w tablicy było 10 000 to ilość powtórzeń jednego elementu wynosiła 100). Skoro już była tablica "prawie" posortowana w sposób rosnąco to następnym typem danych była tablica posortowana z sposób malejąco, ale pierwszy element wynosił 0 (decreasing). Analogicznie, do następnego typu danych wprowadzono modyfikację poprzez powtarzanie tych samych elementów (decreasing-repeated). Ostatnim typem danych była tablica składająca się z jedynki i samych zer (onezero). Algorytm o nazwie BuildInNet to standardowy algorytm sortowania listy przygotowany przez MS i jest on zaimplementowany jako agorytm Quicksort.

Poniżej jest przedstawiony wykres w skali logarytmicznej z czasem działania algorytmów dla losowo wygenerowanych danych. Oś odcięta stanowi grupę ilości danych ( odpowiednio 10, 100, 1 000, 10 000 i 100 000 elementów w tablicy), a oś rzędnych przedstawia czas działania algorytmu w milisekundach.



A poniżej są tablice z wynikami sortowania. Wartości czasu sortowania są przedstawione w milisekundach.


Jak widać w poniższej tablicy, wprowadzenie powtarzalnych elementów nie zmienia znacząco czasu działania algorytmów.





Jak widać na powyższych tabelkach, 3 algorytmy działają stosunkowo długo oraz nie mają znaczenia czy dane są posortowane w postaci rosnąco czy malejąco. Te algorytmy to: Odd-Even sort, Selection i Stooge sort. Takie algorytmy jak Quicksort, BuildInNet Counting i ShellSort działają równie szybko dla tablicy prawie posortowanej rosnąco jak i malejąco. Dla tablicy z jedną modyfikacją (onezero) oraz z prawie posortowaną tablicą (increasing), selection sort ma gorszy wynik czasu sortowania niż dla algorytmów bubble sort, comb sort czy sortowanie gnoma, mimo że dla innych danych te algorytmy są szybsze.
Algorytm Stooge sort ma najgorszą złożoność obliczeniową. Dla 10 000 elementów czas działania był o 3 rzędy wielkości większy niż dla słabych algorytmów. Sortowanie zostało zatrzymane dla 100 0000 elementów,gdyż czas sortowania wynosił 489 557 429 ms, a to jest ... strasznie długo. W przybliżeniu stanowi to 5 dni i 15 godzin. Gdy sprawdzałem dane, to okazało się, że dane zostały posortowane do 48 147 elementu. Dla tablicy liczącej do 1000 elementu nie ma znaczenia jaki algorytm zastosujesz z sortowaniu (za wyjątkiem nieszczęsnego stoogesorta).
Do dalszych testów wybrałem 6 najlepszych algorytmów. W śród nich są: Counting, Quicksort, Shellsort, Mergesort, Insertsort i dla porównania BuildInNet (algorytm Quicksort w BCL). Poniższy wykres przedstawia czas sortowania w skali logarytmicznej dla poszczególnej ilość danych (1000, 10 000, 100 000 i 1 000 000 elementów).





Z tego można wybrać 4 najlepsze algorytmy. Poniżej wykres dla tablicy z danymi losowymi (random) w skali liniowej (OY przedstawia czas działania algorytmu w milisekundach).




W trakcie przerwy w pisaniu algorytmów miałem możliwość zainteresowania się tańcami ludowymi:)








Bardzo mi się podobają filmiki przedstawiające algorytmy sortowania za pomocą tańców. Jestem bardzo ciekaw jak można by było przedstawić jakiś algorytm za pomocą ruedy z salsy :) Może problem ucztujących filozofów.

wtorek, 27 marca 2012

i++ czy i--

Chciałem sprawdzić czy pętla z i++ oraz i-- są sobie równe. Dlatego zrobiłem mały test:
            //Test dla i++
            Stopwatch s1 = new Stopwatch();
            s1.Start();
            for (int i = 0; i < lim; i++)
            {
                //code
            }
            s1.Stop();
            Console.WriteLine("Time for i++: {0} ms",
                    s1.ElapsedMilliseconds);
            //Test dla i--
            Stopwatch s2 = new Stopwatch();
            s2.Start();
            for (int i = lim - 1; i >= 0; i--)
            {
                //code
            }
            s2.Stop();
            Console.WriteLine("Time for i--: {0} ms",
                    s2.ElapsedMilliseconds);
Dodałem możliwość powtarzania tego testu. Obliczenia powtarzałem z 10 razy, aby wyniki były bardziej wiarygodne.
           int lim = int.MaxValue; //2147483647

            long time1 =0, time2=0;
            List<long> gList1 = new List<long>();
            List<long> gList2 = new List<long>();

            for (int i = 0; i < 10; i++) //powtarza 10 razy
            {
                TestFor(lim, ref time1, ref  time2);
                gList1.Add(time1);
                gList2.Add(time2);
            }
            var avgPlus = gList1.Average();
            var avgMinus = gList2.Average();
            var maxPlus = gList1.Max();
            var maxMinus = gList2.Max();
            var minPlus = gList1.Min();
            var minMinus = gList2.Min();

            Console.WriteLine(new { avgPlus, maxPlus, minPlus }); 
            // wyświetla wyniki dla i++

            Console.WriteLine(new { avgMinus, maxMinus, minMinus });
            // wyświetla wyniki dla i--

Jednostki w przedstawionych wynikach są liczone w milisekundach.
1) Brak operacji w pętli.
{
avgPlus = 5084,
maxPlus = 5178,
minPlus = 4998
}
{
avgMinus = 6747,
maxMinus = 6828,
minMinus = 6677
}

Operacja i++ jest szybsza. Czasy dla operacji i++ są około 1,7 sekundy mniejsze niż dla operacji i--.

2) Prosta operacja zawarta w pętli.
            int iter = 0;
            iter++;

{
avgPlus = 6368,
maxPlus = 6494,
minPlus = 6319
}
{
avgMinus = 5472,
maxMinus = 5600,
minMinus = 5446
}
Wyniki są odwrotne do wyników z poprzedniego testu. W tym przypadku operacja i-- jest szybsza. Ciekawe jest, że wyniki dla prostej operacji w pętli są lepsze niż dla pętli bez operacji.

3) Operacja na stringu.
            "ab".Replace('a','b');

{
avgPlus = 127846,3,
maxPlus = 136981,
minPlus = 125358
}
{
avgMinus = 125099,2,
maxMinus = 131357,
minMinus = 123913
}
Badanie potwierdza wnioski z punktu 2, że operacja i-- jest szybsza od i++.

4) Skoro była inkrementacja w pętli to sprawdziłem dekrementacje.
            int iter = 0;
            iter--;

{
avgPlus = 6237,4,
maxPlus = 6260,
minPlus = 6225
}
{
avgMinus = 5337,6,
maxMinus = 5383,
minMinus = 5298
}
Badanie potwierdza wniosek z punktu 2. Operacja dekrementacji jest szybka od operacji inkrementacji.

5) W ciele pętli jest tworzenie obiektu.
{
avgPlus = 52622,
maxPlus = 54548,
minPlus = 51284
}
{
avgMinus = 51557,1,
maxMinus = 55958,
minMinus = 50173
}
Ostatnie badanie potwierdza, że operacja dekrementacji jest szybsza od operacji inkrementacji.

Jak na razie nie wiem dlaczego tak się dzieje. Gdyby ktoś wiedział dlaczego operacja dekrementacji jest szybsza, to proszę o kontakt.