Günther's profileGünther Foidl (gfoidl)PhotosBlogGuestbookMore Tools Help

Blog


    December 07

    Winter break

    Hi everybody,

    now it's gonna be racing time until early May 2010. Informations are available here. I won't report about the races in this blog because this one should remain scientific.

    Ostarrichi-Draken Promo

    I wish you all the best!

    Cheers,
    Günther

    Warum wechselte ich von Fortran nach C#?

    Fortran ist eine wunderbare Programmiersprache die nur eines kann: Rechnen – und das sehr schnell. Mehr kann Fortran nicht.

    Vor allem für numerische Aufgaben bietet die Sprache von Fortran sehr viele eingebaute Funktionen und dies ist ungemein hilfreich. Die Compiler (ich habe den Lahey Fujitsu Fortran Compiler verwendet) sind hochoptimierend. Bei dem von mir verwendeten Lahey-Paket sind weiters hoch optimierte Numerik-Packages inkludiert mit denen sich richtiger Hochleistungscode erstellen lässt – und das habe ich auch gemacht.

    Es stellten sich mir immer die selben Fragen:

    1. Wie bekomme ich die Rohdaten in mein Fortran-Programm?
    2. Wie verarbeitet ich die Daten nach der Berechnung?

    Von Fortran selbst gibt es nur Unterstützung für das Lesen und Schreiben von Dateien, sowohl ASCII als auch binär. Gut mit dem ASCII-Format lassen sich CSV-Dateien verarbeiten, aber das reicht in der heutigen Zeit nicht unbedingt aus. Wie wäre es mit direktem Zugriff auf eine Datenbank? Geht über ein Zusatzpaket wie f90SQL, allerdings arbeitet man da ganz unten auf der ODBC-Ebene und ist somit wenig komfortabel – geht allerdings. XML? Über den ASCII-Weg lösbar – praktisch ist dies aber nicht.

    Das Ergebnis einer Berechnung sind Zahlen – nackte Zahlen die nicht viel Aussagen. Ein Bild wäre hier sehr angebracht. Das ist aber nicht ohne weiters möglich, denn die Sprache sieht dafür nichts vor.

    Für Fortran gibt es sehr viel OpenSource-Code der zusammengesucht werden will um sich somit eine Art “Framework” zu erstellen. Dies ist aber eine sehr mühselige Aufgabe – davon abgesehen dass man wissen muss was es gibt denn zielloses Suchen nach irgendwelchen Neuigkeiten führt selten zum Ziel ;)

    Vor fast zwei Jahren und im Zuge eines neuen Projektes stieß ich mit Fortran an die Grenzen. Ich wusste dass es Fortran.net gibt und meine Lahey-Installation bot dies auch. Mehr als ein wenig rumspielen war für mich nicht drin, denn die für .net erweiterte Syntax von Fortran war sehr gewöhnungsbedürfig und machte mir keinen Spass. Die grundlegende Syntax von Fortran ist sehr logisch und einfach aufgebaut. Englischkenntnisse reichen um die Sprache zu beherrschen. Gut ein wenig mehr gehört schon dazu ;) Durch die Erweiterungen für .net wurde die Sprache ein wenig vergewaltigt. Um es auf den Punkt zu bringen: Fortran ist dafür nicht gedacht.

    Seit jeher entwickelte ich meine Fortran-Programme mit Hilfe von Modulen um eine gewisse Ordnung und Wiederverwendbarkeit zu erzielen. Dieser Stil war auch von OOP inspiriert obgleich es mit OOP nichts zu tun hatte. Meiner Meinung nach lassen sich größere Projekte ohne OOP nur sehr schwer umsetzen und daher ergibt es sich fast zwangsläufig sich in diese Richtung zu orientieren.

    Wie erwähnt stieß ich mit Fortran an die Grenzen und ich hielt Ausschau nach Alternativen. .net war mir durch die Spielerei mit Fortran.net ein wenig bekannt und ganz besonders gefiel mir das Framework, welches für die meisten wiederkehrenden Aufgaben vorgefertigten Code anbot. Zudem lässt sich mit “der” .net-Sprache C# auch wunderschön OO programmieren.

    Somit sind/waren meine Hauptbeweggründe C# zu lernen und zu verwenden

    • das Framework das bei .net angeboten wird
    • C# als intuitive und objektorientierte Sprache

    Der C#-Compiler ist zwar dumm denn er übersetzt den Code “nur” nach IL-Code und der JITer fürht wenige Optimierungen durch – da dies zur Laufzeit geschieht und somit ein Kompromiss zwischen Verzögerung und Optimierung gefunden werden musste – und dennoch ist C# mittlerweile meine Standardsprache für numerische Berechnungen. Die Zeit für die Berechnung hinkt zwar jener im Vergleich zu Fortran weit hinterher, aber die Berechnung ist nur ein Teil der Gesamtaufgabe und diese gilt es zu betrachten. Dazu gehören Einlesen von Daten, Berechnungen und letztendlich die Ausgabe. Über diesen Zyklus gesehen ist C# im Vorteil. Betrachtet man auch noch den Programmieraufwand der sich bei C# durch die Klassen des Framework im Vergleich zu Fortran erheblich verkürzt ergibt sich ein weiterer bedeutenden Vorteil. Dies geht auch Hand in Hand mit den Vorteilen die sich durch OOP ergeben.

    Warum nicht Fortran.net?
    Wie erwähnt gefällt mir die Syntax nicht und ich denke jeder der die Vorzüge von Visual Studio und Intellisense, etc. schätzen gelernt hat will diese nicht mehr vermissen. Weiters finde ich dass Fortran.net eine Vergewaltigung der Sprache ist und die Vorteile des hoch-optimierenden Compilers fallen zum Teil auch weg. Hinzu kommt dass einige Sprachfeatures für die Matritzen-/Tensorrechnung nicht unterstützt werden.

    Was wünsche ich mir von .net/C#?
    In Hinsicht auf die Numerik habe ich zwei Wünsche an C#:

    1. Unterstützung bei Array-Manipulationen:
      Im Laufe der Zeit habe ich eine kleines Framework (besser Base Class Library ;)) für diese Aufgaben erstellt die zum Teil eine Nachbildung der Fortran-Funktionen sind. Beispielsweise wäre die Initialisierung eines Arrays mit einem Befehl schon eine Erleichterung.
    2. Optimierungen des C#-Compilers:
      Wie oben kurz angeschnitten ist es verständlich dass der JITer keine aufwändigen Optimierungen durchführen kann. Diese Aufgabe könnte aber problemlos der C#-Compiler übernehmen. Einziger Nachteil dabei wäre dass der Code im Reflector nicht mehr dem entspricht der geschrieben wurde. Ich denke jedoch dass dies sicherlich nicht der Beweggrund für den Verzicht auf Optimierungen sind.
      Würde der C#-Compiler die IL-Ausgabe optimieren bräuchte der JITer den Code nur nach Maschinencode übersetzen und zur Laufzeit ergäben sich somit auch Vorteile.
      Es ist klar dass der C#-Compiler keine architekturspezifischen Optimierungen durchführen kann/darf, aber es gibt genügend andere Optimierungen wie zB Inlining, Schleifenmanipulation, Ersetzung von Divisionen durch Konstaten durch Multiplikationen,  etc.

    All dies lässt sich zwar selbst im Code durchführen (auch durch eigene Methode, Klassen) aber dies macht den Code nicht unbedingt leserlicher. Leserlicher Code sollte jedoch immer im Vordergrund stehen! Daher ist es naheliegend dass der Compiler dies übernimmt und dabei kann auch unleserlicher IL-Code entstehen. Nichts anderes passiert zB beim yield-Schlüsselwort und bei LINQ. Daher sehe ich kein Problem darin.

     

    Kurz zusammengefasst kann ich festhalten:
    Fortran ist eine wunderschöne Sprache die extrem schnell rechnen kann, aber gegen den Alleskönner C# generell im Nachteil ist.

     

    Gruss,
    Günther

    November 18

    Simulated Annealing

    Auf myCSharp.de habe ich einen Artikel über Simulated Annealing veröffentlich. Siehe http://www.mycsharp.de/wbb2/thread.php?threadid=78641

    Viel Spass!
    November 01

    Ich bin auf Wikipedia

    Anders als gewohnt einmal kein Beitrag im Sinne der Programmierung:

    Dank Jürgen Thomas gibt es einen Wikipedia-Artikel über mich und meine Speedski-Karriere. Siehe: Günther Foidl

    Ich fühle mich geehrt da ich Jürgen sehr schätze obwohl ich ihn persönlich nicht kenne - die Bekanntschaft basiert auf unserer gemeinsamen Tätigkeit in Programmier-Foren.

    Auf diesem Wege bedanke ich mich recht herzlich bei ihm.

    October 18

    Sammon's Projection

    Sammon's projection is a nonlinear projection method to map a high dimensional space onto a space of lower dimensionality.

    The full article:
    Sammon Projecton on codeproject.

    Happy projecting ;)
    October 17

    Bees algorithm

    I've just encountered a interesting looking algorithm for optimization: The Bee algorithm.
    Quite easy to implement - but I have to do further studies on this algorithm to provide more information.

    The principle is - what a wonder - inspired by bees. Mathematically speaking it can said that the search space is split into smaller spaces whereupon these spaces are explored by the bees. The best position in each space is kept and a next iteration is done until a quality criterion is met.

    The above link provides further information and some visual demos on how the algorithm works.

    Sssss

    October 07

    Graustufenbild mit Falschfarben einfärben


    Die PDF-Version kann hier heruntergeladen werden.

    Happy coding ;)
    September 14

    Particle swarm optimization - an improvement to the algorithm?

    See also: Particle swarm optimization for function optimization

    A short introduction to my idea of improving the algorithm  - further studies have to be done before a full-article can be provided.

    The general rule for updating the particles velocity is:


    In the literature two options are common:

    • gBest is the current best solution of the swarm or
    • gBest is the best solution the swarm found so far

    The latter lets the algorithm converge faster but the possibility to get stuck (or trapped) in a local optimum raisen. The first option is the classic approach and the exploration of the search-space is higher.

    In my proposed improvement there’s added another term in the equation for updating the velocity:


    In this formula c3 is the acceleration coefficient giving the tendency to follow the best solution found so far – aBest (absolute Best), r3 is a even distributed random number in the interval 0 to 1 and x the current position. When c3 = 0 the term vanishes and so the equation is equal to the general rule. c3 = 1 & c2 = 0 goes to the second option. Therefore it’s possible to take the advantages of both option into account. Starting with c3 = 1 to converge fast in the first iterations and then decrease c3 towards 0 so the exploration increases, thus avoiding getting stucked in local optima.
    For a static approach I suggest to choose c3 = 0.5.

    As mentioned above further investigation have to be done – I’m going to post updates until the article is ready.

     

    Happy coding Cooles Smiley






    September 10

    Particle swarm optimization - Article, and other algorithms

    As promised in the previous post I've writte an article at codeproject: Particle swarm optimization for function optimization

    There exists other fascinating algorithms for optimizing functions such as:
    • ant colony optimization (discrete problems)
    • genetic algorithms (continous and discrete problems)
    • simulated annealing (continous and discrete problems)
    • great deluge algorithm (continous and discrete problems)
    • artificial immune system (similar to a genetic algorithm)
    If picked out of these the particle swarm because for me it's really impressive to watch the particles exploring the search space - hey it's artificial life ;)

    On performance considerations simulated annealing is my favorite.
     It's so fast that I can't provide a video for minimizing functions. But when you're familiar to the traveling salesman problem than you know how long the classic combinatorial approch takes. When a computer would take one hour for 30 cities then it would take 40 days for 32 cities. Incredible that a computer needs so long. Watch the video and see how simulated annealing finds the solution for 500 (yes really 500) cities within seconds. I haven't used the classic simulated annealing algorithm, but instead an improved version of mine. Therefore I won't show the code right now - maybe later, now it's may baby ;)
      

    The next video shows the same problem - but wiht 100 cities only - with a genetic algorithm (GA) on the left side and simulated annealing (SA) on the right side. You may wonder why SA is by times faster than the GA. The most obvious reason is that SA uses one solution-vector whereas GA uses on vector for each chromosome. A the population used consists of 1000 chromosomes. Thus the GA needs to store 1000 times the solution vector which reduces the speed. When compared by iterations/generations the GA is the one that needs less cycles. Oh, I've stuck to writing - now the video...
      

    I can't promise but I've planned to produce a series of posts concerning computational intelligence. Coverd will be:
    • evolutionary algorithms
    • other meta heuristic approches
    • neural networks
    • training of neural networks
    Hoping that I find time to do this.


    Happy coding Cooles Smiley




    September 08

    Particle swarm optimization - A primer

    While playing around with particle swarms I've created a small application that visualizes how the swarm searches for a global minimum in function R² -> R. It fascinated me looking on the behaviour of the artificial swarm.

    The video shows how a particle swarm searches for the global minimum. Every yellow dot is a particle and the red dot shows the global minimum found so far.
    The function plot colors  high values in red while low values are blue. So the swarm should find the global minimum in a deep blue region. Severel cycles are shown.

         

    When I have mor spare time I'm going to provide a guide to "particle swarm optimization". It sounds very difficulty - but it isn't.
    Compressing the idea behind particle swarms the I can write:
    • a particle is dumb and just remebers the best position where it has been so far
    • when particles form a swarm - i.e. a swarm consists of particles - then the swarm only has knowledge about the best position of any particle in the swarm
    • with this little information each particle alters its velocity to follow the leader (the one with the best position) and keep a reamining component to follow its own best position
    Well that's it - really compressed down. I'll give more information and examples in future posts (time dependent).

    Cu,
    Günther


    September 07

    Performancevergleich Fortran – C#

    Unter http://www.mycsharp.de/wbb2/thread.php?threadid=75886 führe ich eine interessante Diskussion (oder Monolog? ;) über die Performance von C# im Vergleich mit Fortran 95.

    Weiterführende Betrachtung basierend auf diesem Artikel sind in Thomas Enzinger's blog zu finden.


    Happy coding ;)


    August 31

    HashSet<T> und eigene Typen

    Anmerkung: Selbiges gilt auch für den Schlüssel TKey im Dictionary<TKey, TValue>!

    Das HashSet<T> stellt eine leistungsstarke Auflistung dar bei Operationen wie Hinzufügen, Prüfung ob ein Element bereits vorhanden ist, etc. einen O(1)-Vorgang dar. Im Vergleich dazu wären diese Operationen bei einer List<T> O(n)-Vorgänge.

    Für die .net-Standardtypen kann das HashSet<T> problemlos verwendet werden. Wie schaut die Sache aber mit eigenen Typen aus? Schauen wir uns ein Beispiel an:

    Der eigene Typ:

       1: class FooWrong
       2: {
       3:     public int n { get; set; }
       4: }

    Der erste Versuch mit dem HashSet<T> zu arbeiten:

       1: FooWrong fooWrong1 = new FooWrong { n = 3 };
       2: FooWrong fooWrong2 = new FooWrong { n = 3 };
       3: int hash1 = fooWrong1.GetHashCode();
       4: int hash2 = fooWrong2.GetHashCode();
       5:  
       6: HashSet<FooWrong> hsWrong = new HashSet<FooWrong>();
       7: bool add1 = hsWrong.Add(fooWrong1);
       8: bool add2 = hsWrong.Add(fooWrong2);

    Es werden Instanzen des eigenen Typs erstellt mit den jeweils identen Werten. So erwarten wir dass beide Instanzen ident sind. Werden nun aber diese Instanzen zum HashSet hinzugefügt so sind beide enthalten – komisch denn das HashSet sollte doch nur Elemente haben die einzigartig sind.

    Woher kommt das?
    Das HashSet vergleicht zuerst die HashWerte der Objekte und falls diese gleich sind wird der Vergleich der Objekte mittels Equals durchgeführt. Dies geschieht indem die Default-Eigenschaft des IEqualityComparers<T> ausgewertet wird. Da wird keine Implementierung bzw. Überschreibung von GetHashCode angegeben haben wird die Methode vom Basistyp (hier: System.Object) verwendet. Dieser liefert korrekt unterschiedliche HashWerte für die beiden Instanzen da sie nicht die gleiche Referenz sind.

    Nun kann dem HashSet eine Instanz eines IEqualityComparers<T> übergeben werden oder die Default-Eigenschaft erstellt die Instanz von selbst wenn der Typ die IEquatable<T>-Schnittstelle implementiert. Um obiges Beispiel korrekt zu machen sollte der Code also wie folgt geschrieben werden:

    Der eigene Typ (implementiert IEquatable<T>):

       1: class FooCorrect : IEquatable<FooCorrect>
       2: {
       3:     public int n { get; set; }
       4:  
       5:     public override int GetHashCode()
       6:     {
       7:         return n.GetHashCode();
       8:     }
       9:  
      10:     #region IEquatable<FooCorrect> Member
      11:     public bool Equals(FooCorrect other)
      12:     {
      13:         if (other == null)
      14:             return false;
      15:  
      16:         return this.n == other.n;
      17:     }
      18:     #endregion
      19: }

    Gewünschte Arbeit des HashSets:

       1: FooCorrect fooCorrect1 = new FooCorrect { n = 3 };
       2: FooCorrect fooCorrect2 = new FooCorrect { n = 3 };
       3: hash1 = fooCorrect1.GetHashCode();
       4: hash2 = fooCorrect2.GetHashCode();
       5:  
       6: HashSet<FooCorrect> hsCorrect = new HashSet<FooCorrect>();
       7: add1 = hsCorrect.Add(fooCorrect1);
       8: add2 = hsCorrect.Add(fooCorrect2);

    Da dem HashSet keine Instanz eines Vergleichs übergeben wird verwendet das HashSet eine Instanz des Comparers der über die IEquatable<T>.Default-Eigenschaft erstellt wird. Wie bereits erwähnt wird diese Instanz aus der Schnittstelle IEquatable<T> erstellt.

    Happy coding ;)

    August 20

    Ausdrucksbäume erleichtern die Arbeit (Exception-Handling)

    Wie bereits im Blog-Eintrag zu INotifyPropertyChanged verwendet und gezeigt können Ausdrucksbäume auch für das Exception-Handling verwendet werden.

    Beispiel für eine typische Methode:

       1: public void Foo(object argument)
       2: {
       3:     if (argument == null)
       4:         throw new ArgumentNullException("argument");
       5:     ...
       6: }

    Mich stört daran wieder dass ich im Konstruktor für ArgumentNullException der Paramater als String-Literal angegeben werden muss. Vor allem wenn der Code rafactored wird gibt es Probleme.

    Durch Verwendung von Lambda-Ausdrücken kann dies sicherer geschrieben werden. Dazu erstelle ich mir eine (statische) Hilfsklasse:

       1: internal static class ExceptionHelper
       2: {
       3:     internal static ArgumentNullException ArgumentNull<T>(Expression<Func<T>> exp)
       4:     {
       5:         return new ArgumentNullException(GetParamName(exp));
       6:     }
       7:     //---------------------------------------------------------------------
       8:     private static string GetParamName<T>(Expression<Func<T>> exp)
       9:     {
      10:         MemberExpression me = exp.Body as MemberExpression;
      11:         return me.Member.Name;
      12:     }
      13: }

    In dieser Klasse wird in der Methode GetParamName<T> die Expression “zerlegt” und der Bezeichner des Members als String zurückgegeben.
    Über die Methode ArgumentNull<T> wird die Exception erstellt. Der Vorteil der Hilfsklasse ist dass somit alle Exceptions einer Anwendung zentral erstellt werden können (don’t repeat yourself) und weiters ist es somit einfach möglich die Exceptions zu lokalisieren.

    Die Methode Foo (das Beispiel) änder sich zu:

       1: public void Foo(object argument)
       2: {
       3:     if (argument == null)
       4:         throw ExceptionHelper.ArgumentNull(() => argument);
       5: }

    Es ist ersichtlich dass beim Refactoring die Exception korrekt geworfen wird – eine Änderung des String-Literals (da nicht vorhanden) ist nicht nötig.

    Happy coding ;)


    August 14

    Kritische Gedanken zur Task Parallel Library (TPL)

    Mit .net 4.0 ist es für jeden möglich Parallelverarbeitung durchzuführen ohne dass die grundlegenden Kenntnisse von Threading existieren. Dieses und weitere solcher Probleme werden in Zukunft immer öfter auftreten da es sehr verlockend und als Hype gilt mit mehreren Threads zu arbeiten.

    Ich bin dennoch der Meinung dass dieses Werkzeug nur dann sinnvoll eingesetzt werden kann wenn die Grundlagen wie zB Threadsynchronisation verstanden werden - auch wenn das Werkzeug viel von den Mechanismen die im Hintergrund tätig sind wegabstrahiert. Ich habe zB noch keinen Artikel über das Task-Parallel-Library gesehen der bewusst darauf eingeht welche Probleme sich parallelisieren und nicht parallelisieren lassen.

    Es ist gut zu überlegen ob die zu verarbeitenden Daten unabhängig voneinander sind - nur dann ist eine Parallelisierung möglich.

    Die TPL ist also ein Werkzeug das Fluch und Segen gemeinsam ist – je nachdem ob man die Hintergründe kennt oder nicht.

    Happy hacking ;)

    August 08

    Anonyme Methoden und Closures

       1: static void Main(string[] args)
       2: {
       3:     int i = 0;
       4:     Action myAction = delegate
       5:     {
       6:         Console.WriteLine(i);
       7:     };
       8:  
       9:     myAction();
      10:     i = 666;
      11:     myAction();
      12:  
      13:     Console.ReadKey();
      14: }

    In diesem Snippet wird eine anonyme Methode erstellt welche auf den Wert der Variablen i zugreift. Wie kann jedoch auf den Wert zugegriffen werden wenn dieser im Kontext der anonymen Method nicht existiert – er wird ja nicht per Parameter übergeben?

    Dies wird dadurch gelöst dass die Variable i auf dem Heap erstellt wird (statt auf dem Stack). Dazu erzeugt der Compiler eine Klasse (werden DisplayClass…) genannt welche als öffentliches Feld i hat. Somit kann sowohl in der Main-Methode sowie in der anonymen Methode zugegriffen werden. Dieses Prinzip ähnelt dem der Closures.

    Definition einer Closure gem. Wikipedia:

    Als Closure oder Funktionsabschluss bezeichnet man eine Programmfunktion, die beim Aufruf ihren Definitionskontext reproduziert, selbst wenn dieser Kontext außerhalb der Funktion schon nicht mehr existiert. Closures „konservieren“ also ihren Kontext.

    Die Definition wird von C# nicht ganz erfüllt denn wie im obigen Beispiel gezeigt wenn sich der Wert von i ändert so ist der Wert in der anonymen Methode auch geändert - i wurde ja auf dem Heap erstellt. Dieser Umstand ist zu berücksichtigen denn die “äußere Variable wird gefangen”. Die Berücksichtigung dessen erfolgt indem eine lokale Kopie der äußeren Variable angelegt wird.

    Inkorrektes Beispiel

       1: static void Incorrect()
       2: {
       3:     for (int i = 0; i < 10; i++)
       4:         ThreadPool.QueueUserWorkItem(delegate
       5:             {
       6:                 Console.WriteLine(i);
       7:             });
       8:     
       9:     Console.ReadKey();
      10: }

    Das Beispiel wird in folgenden sinngemäßen Code kompiliert:

       1: static void IncorrectCompiled()
       2: {
       3:     DisplayClass display = new DisplayClass();
       4:     display.i = 0;
       5:     for (display.i = 0; display.i < 10; display.i++)
       6:     {
       7:         ThreadPool.QueueUserWorkItem(delegate
       8:         {
       9:             Console.WriteLine(display.i);
      10:         });
      11:     }
      12:  
      13:     Console.ReadKey();
      14: }
      15: //---------------------------------------------------------------------
      16: private sealed class DisplayClass
      17: {
      18:     public int i;
      19:     //-----------------------------------------------------------------
      20:     public void Action()
      21:     {
      22:         Console.WriteLine(i);
      23:     }
      24: }

    Es wird somit immer der Wert 10 ausgegeben da dieser Wert nach Beendigung der Schleife dem Wert des öffentlichen Feldes des DisplayClass-Objektes entspricht.

    Korrektes Beispiel

    Um ein korrekte Ausgabe der Werte von [0, 10) zu erhalten muss wie oben angemerkt die äußere Variable lokal kopiert werden.

       1: static void Correct()
       2: {
       3:     for (int i = 0; i < 10; i++)
       4:     {
       5:         int j = i;
       6:         ThreadPool.QueueUserWorkItem(delegate
       7:         {
       8:             Console.WriteLine(j);
       9:         });
      10:     }
      11:  
      12:     Console.ReadKey();
      13: }

    Dieser Code liefert das korrekte Ergebnis und wird zu folgendem kompiliert:

       1: static void CorrectCompiled()
       2: {
       3:     for (int i = 0; i < 10; i++)
       4:     {
       5:         DisplayClass displayClass = new DisplayClass();
       6:         displayClass.i = i;
       7:         ThreadPool.QueueUserWorkItem(delegate
       8:         {
       9:             Console.WriteLine(displayClass.i);
      10:         });
      11:     }
      12:  
      13:     Console.ReadKey();
      14: }

    Es werden also mehrere DisplayClass-Objekte erstellt um den äußeren Zustand gemäß Definition zu fangen. Die Ausgabe ist daher korrekt.

    Wichtiger Hinweis

    Das Verhalten von Closures muss berücksichtigt werden. Dies gilt auch für LINQ-Abfragen – bei diesen wird ja eine anonyme Methode übergeben und somit müssen Closures berücksichtigt werden.

    August 06

    Visualisierung der Daten einer Matrix

    Im Entwickler-Forum hab ich einen Beitrag zum Thema Visualisieren der Daten einer Matrix verfasst. Der Link zum Thema: http://entwickler-forum.de/showthread.php?p=201316#post201316. Es ist auch das Demo-Projekt angehängt.

    Verwendung findet es im konkreten Anwendungsfall in der Visualisierung von Messdaten eines Sensors.

    Nachfolgend dargestellt ist einmal die Graustufendarstellung und die Darstellung mit Verwendung einer Farbskala.

    Unbenannt Unbenannt1

    Happy visualizing ;)

    August 03

    Vergleich von Gleitkommazahlen

    Ich merke immer wieder dass vielen das Verständnis von Gleitkommazahlen fehlt und deshalb oft eine Vergleich mit == durchgeführt wird. Dies ist aber nicht korrekt.

    Beispiel:

    double d1 = 3.3;
    double d2 = 1.1 + 2.2;
    if (d1 == d2)
    Console.WriteLine("gleich");
    else
    Console.WriteLine("ungleich");

    Beim Ausführen des Code wird die korrekte Ausgabe “gleich” erwartet, es erscheint jedoch “ungleich”. Wie ist das möglich? Ist meine CPU defekt?

    Die Begründung in diesem Verhalten liegt darin dass Gleitkommazahlen (float, double) im Rechner nur als Näherung einer reellen Zahl dargestellt werden. Es treten also Rundungsfehler auf. In der Numerik gibt es ganze Kapitel über die Behandlung von Fehlern und der Fortpflanzung. So weit gehe ich hier aber nicht.

    Durchläuft man obigen Code mit dem Debugger und schaut sich die Werte von d1 und d2 an so kann festgehalten werden:

    d1    3.3    double
    d2    3.3000000000000003    double

    Also existiert nur ein kleiner Unterschied in beiden Werten, der Vergleich mit == liefert somit korrekt das falsche Ergebnis.

    Wie werden Gleitkommazahlen verglichen?

    Es liegt somit Nahe einen Vergleich mit einer Toleranz durchzuführen. Dieses Toleranz wird in der Numerik üblicherweise als Epsilon bezeichnet.

    Somit muss obiger Code geändert werden zu:

    if (Math.Abs(d1 - d2) < epsilon)
    Console.WriteLine("gleich");
    else
    Console.WriteLine("ungleich");

    Dies stellt allerdings nur die einfachste (und oft auch falsche Variante) dar. Eine detailliertere Betrachtung hab ich in diesem Foren-Beitrag gegeben.

    Wie groß soll Epsilon gewählt werden?

    Die Datentypen System.Single (float) und System.Double (double) bietet eine Konstante namens Epsilon an. Diese entspricht aber nicht der Definition von Epsilon im Sinne der Numerik. Dieses Epsilon stellt die kleinste positive von 0 verschiedene Zahl dar.

    Epsilon im Sinne der Numerik wird wie folgt berechnet:

    public static double Epsilon()
    {
    double tau = 1.0;
    double walt = 1.0;
    double wneu = 0.0;

    while (wneu != walt)
    {
    tau *= 0.5;
    wneu = walt + tau;
    }

    return 2.0 * tau;
    }

    Es wird die Schleife so lange durchgeführt bis zwei Gleitkommazahlen als gleich erachtet werden. Dieses Epsilon (kann natürlich auch für float errechnet werden) sollte für Vergleiche von Gleitkommazahlen verwendet werden.

    Epsilon für float: 1,192093E-07
    Epsilon für double: 2,22044604925031E-16

    Happy coding ;)

    August 02

    PEX – Tool mit dem Unit-Test automatisch generiert werden

    Ein sagenhaftes Tool von Microsoft Research. PEX – ein Blick für jeden Unit-Tester - und die es werden wollen lohnt - sich.

    Geht auch im CommandLine-Modus super.

    Da ich mich gerade mit diesem Tool spiele kann ich noch keine Beispiele posten – ist aber auch nicht nötig denn die Dokumention beschreibt alles ausführlich (oder im Getting Started ausreichend) so dass durch “spielendes Lernen” keine Anleitung nötig sein sollte.

    Das einzige was ich schade finde ist dass ich jetzt auf NUnit verzichten kann – welch ein schönes Tool das war….;)

    Happy testing ;)


    Rechnen mit der Grafikkarte (GPGPU)

    In heutigen PCs steckt mit der Grafikkarte gewaltiges Rechenpotential das nicht nur für Computergrafik verwenden werden kann. Nachfolgend wird beispielhaft gezeigt wie mit der Grafikkarte Matritzen multipliziert werden können.

    Warum mit der Grafikkarte rechnen?

    Beim Vergleich der Leistungdaten einer Grafikkarte wie zB die Geforce GTX 285 mit einer Leistung von 1062,7 GigaFLOPS [1] und einem Pentium 4 mit 3,2 GHz der “nur” auf 6,4 GigaFLOPS kommt wird klar dass dieses Potential genutzt werden kann.

    Warum ist die Grafikkarte (GPU – graphics processing unit) so schnell?

    Eine CPU ist universell ausgelegt und kann prinzipiell alles berechnen während GPUs auf Computergrafik optimiert sind. Zudem arbeiten GPUs als Vektorprozessoren und sind somit hochgradig parallel.

    Wie kann mit der Grafikkarte gerechnet werden?

    In den Anfängen von GPGPU wurden Float-Arrays in Bitmaps verpackt um somit eine beliebige Anwendung als Grafikproblem zu tarnen. Wie man sich leicht vorstellen kann ist das Tarnen als Bitmap eine eher schwierige Aufgabe denn das Ergebnis wieder korrekt aus dem Bitmap zu entpacken ist schon eine Kunst.

    Mit dem Projekt Accelerator von Microsoft Research wird dieses Verfahren verwendet.

    Firmen wie zB Nvidia haben erkannt dass GPGPU ein neues Geschäftsfeld sein kann und bieten eine Programmierschnittstelle (API) an. Im Falle von Nvidia ist dies die Compute Unified Device Architecture [2]. CUDA ist eine Erweiterung für die Programmiersprache C aber es gibt glücklicherweise einen Wrapper für C# – CUDA.net. Diese Variante kann nur verwendet werden wenn eine Nvidia-Grafikkarte vorhanden ist. Zusätzlich muss das SDK dazu während der Entwicklung vorhanden sein.

    Mit diesen zwei Projekten steht die Möglichkeit für GPGPU für jeden zur Verfügung. Es liegt aber beim Entwickler abzuwägen ob die Aufgabe für GPGPU geeignet ist.

    Ich finde die Verwendung von Accelerator angenehmer da diese auf DirectX aufsetzt und somit keine Bindung zu einer spezifischen Grafikkarte existiert. Bei CUDA ist es außerdem nachteilig dass in einer C++-ähnlichen Syntax mit der Grafikkarte interagiert werden muss.

    Beispiel

    Als Beispiel sei der “Klassiker” für die Parallelisierung – die Matritzenmultiplikation – mit dem Accelerator-Projekt implementiert. Das Projekt besteht nur aus einer DLL und ist somit einfach zu verwenden – es braucht nur die Assembly eingebunden werden (Verweis hinzufügen).
    Der Code ist relativ einfach:

       1: public float[,] MatMul(float[,] a, float[,] b)
       2: {
       3:     // GPU aktivieren:
       4:     ParallelArrays.InitGPU();
       5:  
       6:     // Die Matritzen für die GPU erstellen:
       7:     DisposableFloatParallelArray x = new DisposableFloatParallelArray(a);
       8:     DisposableFloatParallelArray y = new DisposableFloatParallelArray(b);
       9:  
      10:     // Matrix Multiplikation durchführen:
      11:     FloatParallelArray z = ParallelArrays.Multiply(x, y);
      12:  
      13:     // Das Ergebnis der GPU-Berechnung "greifbar" machen:
      14:     float[,] c;
      15:     ParallelArrays.ToArray(z, out c);
      16:  
      17:     // Speicher freigeben:
      18:     x.Dispose();
      19:     y.Dispose();
      20:  
      21:     // GPU deaktivieren:
      22:     ParallelArrays.UnInit();
      23:  
      24:     return c;
      25: }

     

    Siehe auch

    Quellenverzeichnis:

    [1] Nvidia-GeForce-200-Serie (Leistungdaten)