C++Guns – RoboBlog blogging the bot

23.03.2017

Antwort auf eine alte Frage

Filed under: Allgemein — Tags: , — Thomas @ 08:03

Heute morgen in der Bahn war ich entzückt, denn es ergab sich eine Antwort auf eine Frage die mir irgendwann während der Abi Zeit kam.
Jetzt muss ich mich erst einmal zurück erinnern. Ich hatte damals den Roboter gebaut, dem eigentlich dieser Blog gewidmet ist. Es muss so 2006 gewesen sein, als mir folgende Frage aufkam:
Gegeben sei ein Roboter, der in der Welt herum fahren kann. Aber die Sensorische Bestückung ist sehr schwach. Der Roboter kann nur grob erkennen, wenn vor ihm eine Wand ist. Jetzt fährt also der Roboter los, hat noch keine Wand bisher "gesehen", und weiß sonst auch überhaupt nichts über die Umgebung. Und jetzt detektieren die Sensoren eine Wand. Der Roboter kann nicht drüber fahren. Es ist nicht zu erkennen wie hoch sie ist. Es ist auch nicht zu erkennen wie lange sie sich nach rechts oder links erstreckt. Was soll der Roboter tun? Nach rechts drehen, nach links? Zurück fahren? In eine beliebige Richtung drehen und dann weiter fahren? Kann der Roboter das von sich aus überhaupt entscheiden? Oder soll er einfach stehen bleiben und warten bis die Mauer verschwindet? Kann ja auch passieren. Gegen die Mauer fahren ist übrigens keine Option, da das Robotergesetz ihm verbietet absichtlich Schaden zu verursachen. Noch dazu käme das einen Robotersuizid gleich.

So, das wäre die Frage. Ich kam damals zu keiner befriedigenden Antwort. In eine zufällige Richtung zu drehen und dann weiter fahren erscheint mir am pragmatischsten. Doch woher (guten) Zufall nehmen. Damit hatte ich mich in einer meiner ersten Posts beschäftigt.
Die Natur hat aber eine Antwort parat wie ich heute in "Das Atom der Biologen" [1] gelesen haben. Es geht um Bakterien und Pilze.

Die Reaktion einiger Bakterien auf Licht (Phototaxis). Wenn Chromatium auf eine dunkle Region trifft, stößt es sich zurück, wartet eine Sekunde und schwimmt weiter. In der Pause schwankt es umher (Brownsche Bewegung), so daß sich seine neue Richtung zufällig ergibt.

Na also ^^ Zufällige Richtung ist die richtig Antwort. Aber die Zufallsentscheidung kommt nicht vom Roboter selbst, sondern von der Umgebung. Damit ich sozusagen die Verantwortung, wohin gefahren werden soll, an eine höhere Macht abgegeben worden. Was die Brownsche Bewegung ist und wie sie entsteht, muss noch genauer geklärt werden. Es hat aber irgendwas mit Wärme zu tun.

Natürlich hat die Brownsche Bewegung keinen Einfluss auf einen 5kg schweren Roboter. Aber es ist die Idee die zählt. Jetzt kann ich in diese Richtung weiter arbeiten.

In dem Buch werden übrigens auch andere Bakterien erwähnt die absichtlich sich zum Licht hinbewegen. Also der klassische Licht suchender Roboter. Wenn der Roboter sich also immer zur hellsten Stelle bewegen soll, er also eine Aufgabe bekommt, dann dann entsteht das oben geschilderte Problem nicht, dass irgendwann keine Entscheidung mehr getroffen werden kann, wohin gefahren werden soll? Falsch! :D Stell dir vor, es ist überall gleich hell. Wohin soll er fahren? Zufällige Richtung, oder warten bis es dunkel wird? Andere Situation, selbes Problem.

[1] Fischer - Das Atom der Biologen. S. 191

22.03.2017

Garten - Wasseruhr montiert

Filed under: Allgemein — Tags: — Thomas @ 18:03

Diese seit 1999 nicht mehr geeichte Wasseruhr fristete 18 Jahre ihr einsames Dasein in der Schublade. Nun bekommt sie eine neue Aufgabe: Zähle Wassermengen! Das kann eine Wasseruhr doch gut, auch wenn sie alt ist ^^ Ein paar Adapterfehlkäufe später war die Sache montiert. Sieht auch gar nicht soooo schlecht aus, oder? Jetzt muss nur noch jemand wieder das Wasser im Keller andrehen.

wasseruhr

C++ Guns - Funktionale Anwendung erkannt

Filed under: Allgemein — Tags: — Thomas @ 15:03

Ich habe gerade eine einfache Schleife mit 5 Zeilen geschrieben und auf einmal sah ich, dass das doch ein gutes Beispiel für funktionales programmieren wäre.
Gegeben ist ein Datenvector mit custom Typ und gesucht ist ein bestimmtes Datum und, falls vorhanden, davon ein bestimmter Wert. Die Schleife lässt sich von Hand so ausdrücken:


    struct Blah {
        size_t idx;
        int att;
    };

    vector<Blah> data { {2, -1}, {1, -1}, {5, 50}, {3, 10}};

    // skip -1
    size_t start = 0;
    for(size_t i=0; i < data.size(); ++i) {
        int att = data[i].att;
        if(att != -1) {
            start = data[i].idx;
            break;
        }
    }
    cout << "start " << start << "\n"; // print 5

Hier gibt es gleich eine ganze Reihe von Fehlerquellen. Von welchem Typ muss i sein, size_t oder int? Inkrement mit ++i oder i++ ? Ist der operator[] überhaupt vorhanden, und wenn ja auch effizient? Muss der Zugriff ueber const Referenz erfolgen? Und die Schleifen koennen wir beenden beim ersten Treffer, ja sicher oder ist das "break" zufällig da. Fuer alle das, muss man den Code Zeile fuer Zeile lesen und nachvollziehen und verstehen. Wie immer ist das "WAS und nicht WIE" Prinzip verletzte. Denn der Code sagt nicht, WAS er macht, sondern nur WIE. Ich hätte auch range-for nehmen können. Aber das ändert am Prinzip nichts.

Aus funktionaler Sicht ist die Schleife ja ein Muster fuer "find_if_apply" oder "apply_if_find" je nachdem ^^ Ob es in der funktionalen Welt so eine Funktion gibt, und wie sie genau heißt, weiß ich nicht. Aber ich probier mal meine eigene Version. Ich wäle den Namen "find_if_apply", da es schon eine C++ Funktion std::find_if gibt, und erweitere sie um eine "apply" componente.


template<class Container, class UnaryPredicate, class UnaryFunction>
void find_if_apply(const Container& data, UnaryPredicate p, UnaryFunction f) {
    for(const auto& x : data) {
        if(p(x)) {
            f(x);
            break;
        }
    }
}

size_t start = 0;
find_if_apply(data,
              [](const Blah& x) { return x.att != -1; },
              [&start](const Blah& x) { start = x.idx; }
              );
cout << "start " << start << "\n"; // print 5

Die Funktion find_if_apply nimmt zwei den Datensatz und zwei Funktionen. Die erste ist fuer find, und die zweite fuer apply.
Also die template Funktion selbst ist wirklich überraschend erstauling elegant einfach. Die Anwendung davon ist auch okay. Zwei einzeiler Funktionen sind noch lesbar.

Übrigends, std::find_if alleine hätte nichts geholfen. Da ein Iterator zurueck gegeben wird der wieder den Scope voll müllt und manuell auf Gültigkeit geprüft werden muss. Mit std::find_if wäre die Schleife und das if() weg gekapselt, aber gebracht hätte es nichts.

Noch eine Bemerkung: Die Variable idx in dem Beispiel ist explizit angegeben. Überwiegend kommt das in unseren Datenstrukturen und Algorithmen aber nicht vor. Dort ist die Position im Array der Index. Und schon funktioniert der funktionale Ansatz wieder nicht. Man könnte find_if_apply natürlich so erstellen und dokumentieren, dass das erste Argument der Lambdas der Laufindex ist. Aber nicht immer wird er auch in den Lambdas benötigt. Da mit Overloads und sonstige Tricks kommen macht alles wieder nur viel zu kompliziert. Noch dazu hat nicht jeder Container auch ein Laufindex. Bei Listen funktioniert es ist nicht, und da ist es dann Datenstruktur abhängig, wo der Index des Datums steht.

FORTRAN - QT Software - made my day

Filed under: Allgemein — Thomas @ 13:03

(Nein, nicht The Qt Company GUI Framework)

plusFORT, das Fortran Restrukturierungs- und Analysewerkzeug
ist in der neuen Version 7.0 erhältlich. Ausprobieren kann
man das darin enthaltene SPAG (den "Spaghetti Unscrambler")
auch online

Das ist, als würde man Ärzte speziell ausbilden, um Schussverletzungen in Füßen besser zu behandeln. Anstatt den Leuten das Schießen beizubringen.

21.03.2017

numpad game

Filed under: Allgemein — Tags: , — Thomas @ 09:03

Wer ist schneller beim Zahlen eintippen über den Nummerntastenfeld?
Zwei Tastaturen. Ein Programm zeigt Zufallsziffern an. Wer die Zahl als erstes richtig eingetippt hat, bekommt ein Punkt. Und das Eingabefeld wird bei beiden Spielen gelöscht. Wird ein Fehler bei der Eingabe gemacht, bekommt der Spieler einen Minuspunkt und der andere Spieler hat die Möglichkeit aufzuholen. Return muss keiner drücken. Die nächste Zahl kommt, sobald sie einmal richtig eingetippt wurde.
Ist wie Tetris, nur dass man keine Blöcke richtig positionieren muss, sondern Zahlen richtig eintippen. Strange...

19.03.2017

Gleiswendel - Theoretische Gedanken

Filed under: Allgemein — Tags: — Thomas @ 23:03

Wie könnte man einen Gleiswendel mit Märklin Metallgleise bauen? Als erstes Problem fällt mir da die benötigte Steigung ein. Es soll natürlich schnell an Höhe gewonnen werden. Aber die Steigung darf nicht zu stak sein, sonst schafft es die Lok noch, oder die Waggons entgleisen.

In vielen Büchern lese ich etwas von einer maximalen Steigung von 5% auf gerade Strecke. Nun hat ein Wendelkreis keine geraden Strecken. In Kurven wird immer mal eine maximale Steigung von 3% angegeben. Ehr weniger. Da der Gleiswendel eine einzige Kurve ist, würd ich zu 2% tendieren.

Nur haben die Metallgleise einen fixen Kreisradius, und können nicht wie die Kunststoffgleise in beliebig weiten Kreisen verlegt werden.
Wie viel Prozent Steigung ergibt sich für den Normalradius bei minimaler Durchfahrtshöhe für Oberleitungsbetrieb?

Es gibt Normalkreis 5100 mit 36cm Radius. Den Parallelkreis 5200 mit 43.7cm Radius. Und den Industiekreis mit 5120 mit nur 28.6cm Radius. Aber das Industriegleis ist nicht geeignet. Es lassen sich nur kleine Loks und Waggons darüber fahren. Alle anderen entgleisen. Es wurde von 1953 bis 1957 auch der Großkreis I und II mit einem Radius von 53.5cm und 58.5cm gefertigt. Aber die Gleise konnten sich wohl wegen dem Platzbedarf und Preis nicht halten. Ich bezweifle auch, dass diese Gleise sich heute in einem guten Zustand heute noch aufzutreiben sind. Also bleibt nur der Normal- und Parallelgleis.

Als Durchfahrtshöhe nehme ich 9cm an. Auch hier gibt es stark unterschiedlich schwankende Angaben. Je nach Lok, Gleise und lichter Raum der für die Hand Gottes frei bleiben muss, um die entgleisten Züge wieder einzusetzen. Und das passiert öfter als einem lieb ist...
Eine Steigung von 2% bedeutet 2cm Höhenunterschied auf 100cm Länge. Für 9cm braucht es also 450cm. Das ist schon ganz schön viel. Ein Normalkreis mit 36cm Radius hat einem Umfang von 226.2cm. Also viel zu wenig. Ein Normalkreis Kreis müsste eine Steigung von ca. 4% haben.
Versuchen wir es mit dem Parallelgleis. Durch den größeren Radius ergibt sich auch ein größerer Umfang von 274.6cm Das ist nicht wirklich mehr und entspricht einer Steigung von 3.3%.

Wir müssen den Gleisradius irgendwie größer bekommen, aber gleichzeitig nur die vorhandenen Gleise nutzen. Abwechselnd ein gerades Gleis und ein gekrümmtes könnte funktionieren. Hier ist der Einsatz moderner Software gefragt ;)

Mit Wintrack habe ich zwei weitere Radien gebaut. Einen mit 52cm und einen mit 59cm. Das entspricht einer Steigung von 2.8% bzw. 2.4%. Ich denke, größere Radien machen keinen Sinn mehr. Der Aufbau wird ja schon 1.5m im Durchmesser. Ein Nachteil ist, dass der Zug dann immer ein Stückchen gerade aus fährt, dann wieder ein Stück Kurve, dann wieder gerade aus. Das wackelt dann so.
Die Gleise müssen aber 1a Top in Ordnung sein. Über jeder Verbindung muss der Zug sauber drüber fahren.

gleiswendel

16.03.2017

C++ Guns - std Input/output library

Filed under: Allgemein — Tags: — Thomas @ 19:03

Erstmal ein Link zum Thema. Die sind selten. Copy, load, redirect and tee using C++ streambufs
Und noch einen A beginner's guide to writing a custom stream buffer (std::streambuf)

Also ich muss ganz ehrlich sagen, diese C++ iostream library ist einfach nur scheiße.
Total.... unmöglich damit was gescheites zu machen. Ich meine jetzt nicht std::cout oder die ">>" "<<" Stream Syntax. Nein, man muss das Geschichtlich sehen. Die I/O Library wurde designt, also C++ designt wurde. Ist also neben std::vector und std::string eines der ältesten Sachen in der Sprache. Anders als std::vector und std::string sind diese std::*stream Klassen einfach zu abstrakt geworden. Aber man muss das verstehen. Damals waren virtuelle Klassen und Templates neu, und wann es zuviel des Guten ist, muss man ja auch erst noch herausfinden. So finden sich in der Dokumentation gleich 11 Klassen um Zeug aus/in Datein/String/Streams zu lesen/schreiben. Ich ziehe hier absichtlich den Vergleich zu Qt und Fortran. Ja, Spass muss sein.
Bei Qt gibt es QIODevice als Basisklasse für unter anderem QFile und QBuffer und dazu QTextstream. Wobei QBuffer/Textstream hier ein normalen String meint, so wie es std::basic_stringstream ist. Unter Fortran gäbe es write/read(fhdl/string)...

Jetzt gibt es zwischen std und Qt ganz klare Unterschiede im Design. Fangen wir mit Qt an. Das ist am pragmatischsten.
* Ich will von einer Datei lesen/schreiben, nehm ich QFile.
* Ich will von einem String lesen/schreiben, nehm ich QBuffer/QTextstream.
* Ich will diese tollen Stream "<<" ">>" Operatoren, nehm ich QTextstream.
Und jetzt kommt der clou:
Egal ob man mit Dateien oder Strings arbeitet, die Stream Operatoren funktionieren mit QTextstream immer. Eben WEIL QIODevice als Basisklasse designt wurde.

So weit so gut.

In der C++ I/O Library gibt es Ähnliche Ansätze.
* Ich will von einer Datei lesen/schreiben, nehm ich basic_fstream.
* Ich will von einem String lesen/schreiben, nehm ich basic_stringstream.
* Ich will diese tollen Stream "<<" ">>" Operatoren, ja, sind schon dabei.
Und jetzt kommt der clou:
Egal ob man mit Dateien oder Strings arbeitet, die Stream Operatoren funktionieren immer. Eben WEIL basic_ostream und basic_istream als Basisklassen designt wurden.

Jetzt geht die c++ I/O Library weiter und macht noch die Unterscheidung, ob man nur lesen, nur schreiben, oder beides gleichzeitig will. Und wie es die Philosophie einer streng typ basierten Sprache so will, drückt man das in dem Typ einer Variable aus. Und nicht (nur) mit einer Laufzeit Variablen.

Aus diesem Grund gibt es neben basic_fstram auch basic_ifstram und basic_ofstram.
Und neben basic_stringstream auch basic_istringstram und basic_ostringstream. Und natürlich, neben basic_iostram auch basic_istram und basic_ostram. Damit sind 9 von 11 Klassen gefunden.

Schwachsinn? IMO! Damalig geiles Design um zu zeigen was in der Sprache steckt? Absolut!
Wir kommen zu den Templates.
Ahso, beinah hätte ich Fortran vergessen.
Bei Fortran gibt es write/read(fhdl/string).

Kennt ihr den Unterschied zwischen QString und QBytearray? Beides wird benutzt um "Text" darzustellen. Und QString ist sozusagen die Standardklasse bei Qt. Intern wird ein 16bit Character Type benutzt, statt dem sonst üblichen 8 bit. Das hat einfach den Grund, weil Qt Weltweit agiert. Und entsprechend auch Weltsprachen darstellen muss. Nun gibt es in der Welt viel mehr als 256 darstellbare Zeichen. Also wird ein 16bit Character genutzt.

Der C++ Erfinder hat das 1984 schon gesehen und die I/O Library entsprechend vorbereitet. Ob das die C++ Programmierer nun auch alle verstanden haben, sei mal dahin gestellt. Der Character Typ, ob 8bit oder 16bit, kann über Templates festgelegt werden. Die Anzahl der Klassen steigt also nicht, nur ihr Typ ändert sich.
So entspricht QBytearray std::string und QString entspricht std::wstring. Für alle vorgestellten std steram Klassen gibt es eine "normale "std::istraem" und eine "std::wistrem" Klasse. std::strinstream und std::wstringstream u.s.w.

Man sieht deutlich, dass die Information bei C++ im Type steckt. Ob pragmatisch oder schlecht sei dahin gestellt.
Bei Fortran gibt es write/read(fhdl/string) und hast du es mit ausländische Sprachen zu tun, hast du Pech gehabt.

Es fehlen noch std::basic_ios und std::ios_base. Bei Qt gibt es keine direkten Vergleichs Klassen, da die Implementierungsdetails versteckt sind. Aber bei C++ 1984 war das überhaupt noch kein Thema. Also, std::basic_ios ist eine Basisklasse von allen bisher vorgestellten std:: Klassen. Jede Funktion, die std::basic_ios bereit stellt, haben auch alle anderen Funktionen. Das sind hauptsächlich Funktionen für die Fehlerbehandlung oder den Status des internen Buffers.
Wie gesagt, das ist bei Qt alles weg-abstrahiert. Interne Buffer sind da irgendwo und machen ihren Job. Das ist für den Qt Anwender auch total egal. Hauptsache, man kann lesen/schreiben.
Aber C++ hat ja als Ziel, dass man alles tun kann. Also muss man auch die ganze Kontrolle haben. Und dennoch den Kompfor, dass man sich nicht selbst in den Fuß schießt. Naja.
Wenn bei Qt ein String NICHT in ein Integer konvertiert werden kann, dann passiert entweder garnichts, oder eine optionale logische Variable wird auf false gesetzt.
Bei C++ gibt es die Funktionen good() eof() fail() bad() oder Exception, um zu überprüfen ob alles geklappt hat. Bei Qt gibt es okay, oder nicht okay; zwei Möglichkeiten. Bei C++ gibt 16. Naja, fast. Wie immer ist C++ detaillierter. Wenn etwas nicht good() ist, dann ist es entweder eof() oder fail() oder bad(). Klar, oder?
Aber wenn eof(), dann ist das nicht unbedingt fail() oder bad(). Das Ende der Datei erreicht? Absolut kein Problem. Nun, zwischen fail() und bad() liegt der Unterschied, dass bad() schlechter als fail() ist. bad() impliziert fail(). Wenn bad() ist, dann geht es nicht weiter. Dann geht die Welt unter. Dann ist alles vorbei. Aber mit fail() koennen wir weiter leben. Eine Konvertierung von String nach Integer failt zwar, aber sonst ist alles okay und wir können weiter machen.

Wann genau welcher Fehler auftrifft, kann in der IObase Doku nachgelesen werden.

Nun gibt es seit C++ auch Exception. Alle Google Entwickler mögen hier jetzt bitte sterben. Exceptions bieten die Möglichkeit den Programmteil wo "alles ist gut", von dem Programmteil "Fehlerbehandlung" zu trennen. Liest man dann den Code von Oben nach Unten, liest man nur den Teil, der ausgeführt wird, wenn kein Fehler passiert. Nur das interessiert einem meistens.
Die Exceptions ignoriert man bei Qt komplett. Nun, das ist ein Weltweites Framework welches versucht es jedem recht zu machen. Es sei ihnen verziehen.
Bei C++ hat man, wie immer, die Wahl.

Kommen wir nun langsam zum Kern der Sache, warum ich mich damit beschäftige. Ich möchte einen XYZ Reader bauen, der stumpft pro Zeile drei Zahlen liest. Es sollen immer drei pro Zeile sein. Und ich möchte das mit pure C++ machen, weil Qt nicht überall installiert ist.
Das ist auch absolut kein Problem.


stream >> var1 >> var2 >> var3;

Das funktioniert bei C++ genauso wie bei Qt genauso wie bei Fortran. Nur da müsste man read() schreiben.
Aber was ist mit der Fehlerbehandlung? Wenn irgendwas schief läuft, dann will ich genau wissen, WAS und WO und WARUM es schief lief. Auf dumm herum Raten hab ich kein Bock. Lebenszeit und so.
Ja Scheiße, das funktioniert weder bei C++ noch bei Qt noch bei Fortran gut. Bei Fortran und Qt gib es zwar Statusvariabeln ob etwas schief lief, aber DAS etwas schief lief, muss man noch selbst prüfen. Bei C++ ist das DAS mit exceptions zwar automatisiert, aber es bleibt immer noch das WAS.
Und das WO, z.b. mit Zeilennummern, muss man alles noch selbst implementieren. Ich hätte gerne eine Fehlermeldung wie: "Datei xyz. Zeile: 123. String 'scheisse' kann nicht nach interger konvertiert werden". Ja dann ist alles klar. Und nicht "iostream error". Den Error kanntes dir sonst wo hin stecken.

Wir können dieses Verhalten natürlich selbst implementieren. Eine Zeile einlesen und parsen. Bei Fortran hat man gleich das Problem: Wie groß muss der Buffer sein? BUMM FAIL.
Bei Qt wird eine Kopie für den Buffer angelegt. BUMM Performance FAIL.
Bei C++ kapiert kein Aas wie er das implementieren soll. BUMM BRAINFAIL.

C++ soll performant sein. Und damit meinte ich nicht. "Lade die Webseite mit 4 Bildern und 3 Textzeilen in unter 10 Sekunde". Das ist für Gehirn entfernte Idioten. Ich meinte so etwas wie "Verarbeite eine Milliarden Buchstaben in einer Sekunde".
Und dazu gehört auch, dass Eingabe Daten nicht erst unnütz in einem extra Buffer geladen werden, sondern, dass gleich auf den Daten gearbeitet wird.

Und genau hier komme ich zur abstrakten Vorgehensweise von "Lese drei Zahlen pro Zeile ein". Ein Zeilenende ist durch ein \n gekennzeichnet. Es muss also erst ein Abschnitt gefunden werden, von wo bis zum nächsten \n gültige Daten vorliegen (unformatiertes lesen). Und dann erst kann auf diesem Abschnitt versucht werden, formatiert zu lesen. Also 3 Zahlen zu extrahieren. Diese Erkenntnis selbst, ist für viele schon Brainfuck genug.

Es sollen also folgende Fehler erkannt werden.
EOF bevor 3 Zahlen fertig gelesen wurden.
Newline char bevor 3 Zahlen fertig gelesen werden.
Konvertierungs Fehler von String nach Zahl.

So, und wie wird das Umgesetzt?
Erstmal die Version, welche eine Zeile in ein String einliest und dann parst.
Datei werden die Daten nicht gespeichert, nur eingelesen, geparst und verworfen.
Testdatei mit 772MB, 28895639 Zeilen a 3 Zahlen.

Workrechner:
real 0m44.049s
user 0m43.892s
sys 0m0.176s
17.55 MB/s

real 0m44.965s
user 0m44.760s
sys 0m0.216s
17.16 MB/s

Heimrechner:
real 2m0.688s
user 1m58.776s
sys 0m1.228s
6.38 MB/s

real 1m54.953s
user 1m54.172s
sys 0m0.628s
6.66 MB/s

Wir haben also ein Durchsatz von 17 MB/s bzw. 6 MB/s


std::ifstream ss(fileName);
if(!ss.is_open()) throw();
try {
  ss.exceptions(std::ios_base::failbit);
  for(size_t i=0; i < n and ss.good(); ++i) {
    std::getline(ss, line);
    std::istringstream ss2(line);
    ss2.exceptions(std::ios_base::failbit);
    ss2 >> data[0];
  }
} catch(std::ios_base::failure& ex) {
...
}

Zwei Input streams zu erzeugen kommt mir wrong vor. Aber der eine liest unformatted und der andere formatted.
Aber der formated stream kann ja auf dem Buffer vom unformatted stream Arbeiten. Oder so ähnlich. Eigentlich, ist der newline character ein Zeichen fuer den formated stream. Und nun kann man std::ctype und die std::locale von std::istream so änderen, dass '\n' nicht als whitespace anerkannt wird. Damit es es möglich, Zahl für Zahl einzulesen aber bei '\n' ist schluss. Dummerweise muss man im dann von Hand noch '\n' und restliche whitespaces einlesen. Das führt wieder zu versteckte Fehler. Und die virtuellen Fehler sind eh Performance Killer. Das MUSS besser gehen.

Workrechner:
real 0m32.871s
user 0m32.600s
sys 0m0.276s
23.49 MB/s

real 0m32.776s
user 0m32.576s
sys 0m0.200s
23.55 MB/s

Heimrechner
real 1m37.050s
user 1m33.396s
sys 0m1.512s
7.95 MB/s

real 1m39.499s
user 1m31.360s
sys 0m1.524s
7.76 MB/s

Immerhin von 17 auf 23 bzw. von 6 auf 7 MB/s hoch.

So, habe mit mmap die Inhalt direkt ueber den Speicher zugreifbar gemacht. Zum convertieren nehme ich std::strtod und bals std::from_chars. Die arbeiten direkt auf dem Speicher. Kein dummen rumkopieren in irgendwelche Buffer mehr. Dann schaun wir mal:

Heimrechner
real 0m33.893s
user 0m31.112s
sys 0m0.876s
22.77 MB/s

real 0m30.617s
user 0m29.564s
sys 0m0.356s
25.21 MB/s

Nu schau sich das mal einer an. Von 7 MB/s auf 25 MB/s hoch. Faktor 4 schneller. Dann müsste mein Workrechner locker mit 60 MB/s arbeiten. Mit eingeschalteter Compiler Optimierung ist sogar noch etwas mehr drin.

Der Cluster parst bei eingeschalteter Optimierung die 772 MB in 9.6sec. Das macht stolze 80.4 MB/s!

15.03.2017

Biologie++ - PCR

Filed under: Allgemein — Tags: — Thomas @ 15:03

DNA kann sich vermehren. Das wusste man schon lange. Wie genau das geht ist aber überhaupt nicht so leicht ersichtlich. PCR Polymerase-Kettenreaktion ist eine Methode um die Replikation, die normalerweise in einer Zelle stattfindet, unter kontrollierten Bedingungen im Labor durchzuführen. Dazu wird die original DNA, welche die zu vervielfältigen Abschnitte enthält, sowie Primer und DNA-Polymerase zusammen mit Nucleotide in einem Thermocycler gegeben und mehrmals erhitzt und wieder abgekühlt.
Der Ablauf besteht im wesentlichen aus drei Schritten.
Im ersten Schritt wird die DNA auf 96° (Schmelztemperatur) erhitzt um die Doppelstränge zu trennen. Bei niedriger Temperatur richten sich im zweiten Schritt die (komplementären) Primer an der DNA aus. Die genaue Temperatur wird durch die Länge und der GC-Gehalt der Primer festgelegt. Schließlich wird im dritten Schritt bei erhöhter Temperatur mit Hilfe der DNA-Polymerase der Strang mit komplementären Base wieder aufgefüllt.
Werden die Schritte mehrmals hintereinander ausgeführt, vervielfältigt sich die DNA Kettenreaktionsartig.

Biologie++ - A T C G U

Filed under: Allgemein — Tags: — Thomas @ 10:03

Die Buchstaben A T C G U stehen für die Basen Adenin, Thymin, Guanin, Cytosin und Uracil. Wobei Thymin und Uracil "sich ähnlich sehe" und das letzte nur bei RNA vorkommt.
Diese Moleküle bestehen aus Stickstoff, Sauerstoff, Wasserstoff und etwas Phosphor. Zucker und Klebstoff, die Bausteine des Lebens.

Adenin ist wie Guanin ein Purin. Wohingegen Thymin, Cytosin und Uracil ein Pyrimidin sind. Dabei ist Purin eine heterobicyclische aromatische organische Verbindung mit vier Stickstoffatomen. Wärend Pydimidin eine sechsgliedrige heterocyclische aromatische organische Verbindung mit zwei Stickstoffatomen ist. Adein und Guanin sind also fetter als die anderen ;) So kann sich ein Purin nur mit einem Pyrimidin verbinden. Es existiert also keine A-G Verbindung.

Die Summenformel von Adenin ist C5H5N5, die von Guanin C5H5N5O. Also ein Sauerstoff Atom ist mehr dran. Bei Thymin lautet die Summenformel C5H6N2O2, Cytosin C4H5N3O und Uracil C4H4N2O2.

Adenin bildet zwei Wassserstoffbrücken zu Thymin oder Uracil. Wärend Guanin drei Wasserstoffbrücken zu Cytosin bildet. Es wird also mehr Energie benötigt um eine G-C Verbindung aufzutrennen.

Thymin kann man aus Rinderhirn extrahieren. Genauso wie Radiergummis.

Über ein Phosphor am C5 Atoms des Thymins oder Uracils kann eine Verbindung zu anderen Nucelotides im DNA Strang hergestellt werden.

Guanin ist übrigends das Guano, was bei Fledermäusen hinten raus kommt.

Auch bei Cytosin und Gianin ist über das C5 Atom und Phosphor eine Verbindung zum DNA Strang möglich.

14.03.2017

Diese Woche - 10 Jahre RoboBlog

Filed under: Allgemein — Thomas @ 09:03

Na sowas, sind schon 10 Jahre rum :D

Ich kann mich noch erinnern, als wäre es gestern gewesen, wie wir den Roboter bauten. Vor dem Blog gab es ein RoboWiki. Das gibt plötzlich flöten und seit dem 11.3.2007 haben wir den RoboBlog. Mein aller erster Post war dann am 18.3, und worum ging es? Na um Mikrocontroller.

10 Jahre voller Programmieren, Kuchen, Technik, Eisenbahn und zwischendurch Diverses ^^

Auf die nächsten 0xA Jahre!

« Newer PostsOlder Posts »

Powered by WordPress