C++Guns – RoboBlog blogging the bot

03.02.2017

C++Guns - Pointer of Pointer of ...

Filed under: Allgemein — Tags: — Thomas @ 17:02

Was ist ein Pointer auf ein Pointer auf ein Pointer u.s.w. und wozu braucht man das?
Man braucht es eigentlich nicht. Was es ist, werde ich versuchen hier zu erklären.
Ein Pointer verweist auf ein anderes Objekt. Und dieses Objekt kann mit Hilfe des Pointers manipuliert werden.
Dazu ein kleines Beispiel:


void manipulate(int *x) { *x = 42; }
int x = 2;
manipulate(&a);
cout << a; // print 42

Das Objekt, auf welches der Pointer zeigt, kann auch nachträglich geändert werden. Beispiel


int a=2;
int* p = &a;
cout << *p; // print 2

int b=3;
p = &b;
cout << *p; // print 3

Es ist auch möglich Pointer als Funktionsargument zu nutzen und innerhalb der Funktion den Pointer auf ein anderes Objekt verweisen zu lassen:


int b=42;
void manipulatePointer1(int* p1) {
    p1 = &b;
}
 
int a=2;
int* p = &a;
cout << *p; // print 2

manipulatePointer1(p);
cout << *p; // should print 42, but print 2

So funktioniert es aber nicht. Die Subroutine manipulate1 ändert, worauf der Pointer p1 zeigt. Aber nicht worauf der Pointer p in der aufrufende Routine zeigt. Um das zu erreichen, muss die Adresse des Pointer übergeben werden, statt nur seinen Wert (die Adresse von a). C++ ist eben einen call-by-value Sprache.


int b=42;
void manipulatePointer2(int** p) {
    *p = &b;
}

manipulatePointer2(&p);
cout << *p; // print 42!

Alles klar?

Das Spiel kann man noch weiter treiben und den Pointer durch 3, 4 Funktionen schleusen. Es braucht dafür aber niemals mehr als ein Pointer auf ein Pointer. Da die Adresse des ersten Pointers p, in die Funktionen übergeben wird, und nur diese Adresse wird gebraucht.
Also ein Pointer auf ein Pointer auf ein Pointer ist ein kranker Scheiß, den man nicht nutzen soll.

21.01.2017

How do I sort two vectors containing relative entries, using STL?

Filed under: Allgemein — Tags: — Thomas @ 11:01

How do I sort two vectors containing relative entries, using STL? [1]

Da ich mir kein Account auf stackoverflow machen konnte, (ka. warum es passierte einfach nichts), gibt es jetzt hier die richtige Antwort.
Der Ansatz von Nikos Athanasiou war schon richtig, leider total krank programmiert und mit zu vielen Schleifen. So hat der Algo. quatratische Laufzeit und ist unbrauchbar fuer grosse Datenmengen.
Ich uebernehme seinen Ansatz und tausche nur die Funktion rearrange_vector() aus. So ergibt sich eine linear-logaritmische Laufzeit dominiert durch die Sortierung. Und einen linearen Speicherverbrauch. Da aber nur integer indices gespeichert werden, ist der Zusatzverbraucht sehr gering. Gerade einmal 4byte pro Namen. Also ca. 4MB pro eine Millionen Namen. Das sollte nun wirklich niemand stören.


#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>

using namespace std;

void rearrange_vector(const vector<int> indices, vector<string> &v) {
    for(int idx1=0; idx1 < v.size(); ++idx1) {
        int idx2 = indices[idx1];
        // nur dann tauschen, wenn nicht schonmal getauscht wurde,
        // und wenn ein tausch ueberhaupt notwenig ist
        if(idx2 > idx1) {
            swap(v[idx1], v[idx2]);
        }
    }
}

int main() {
    // 1. Problem space
    vector<string> firstnames = {"Dennis",  "Alexander", "Bjarne",      "James",   "James" };
    vector<string> lastnames  = {"Ritchie", "Stepanov",  "Stroustrup",  "Coplien", "Gosling" };

    // 2. vector of indices - sorted according to the order of firstnames
    vector<int> indices(firstnames.size());
    // create sequenz 0,1,2,3,...
    iota(begin(indices), end(indices), 0);

    sort(begin(indices), end(indices), [&](int i1, int i2) {
        return firstnames[i1] < firstnames[i2];
    });

    // debug
    cout << "Sorted indices\n";
    for(auto i : indices) {
        cout << i << " ";
    }
    cout << "\n";

    // 3. rearrangement according to the sorted indices
    rearrange_vector(indices, firstnames);
    rearrange_vector(indices, lastnames);

    // 4. print results
    for (size_t i=0; i < indices.size(); ++i) {
        cout << firstnames[i] << " " << lastnames[i] << endl;
    }

    return 0;
}

[1] http://stackoverflow.com/questions/25085015/how-do-i-sort-two-vectors-containing-relative-entries-using-stl

22.12.2016

sizeof(int)

Filed under: Allgemein — Tags: — Thomas @ 00:12

According to N3337

3.9.1 Fundamental types [basic.fundamental]
2
There are five standard signed integer types : “signed char”, “short int”, “int”, “long int”, and “long
long int”. In this list, each type provides at least as much storage as those preceding it in the list.
There may also be implementation-defined extended signed integer types. The standard and extended signed
integer types are collectively called signed integer types. Plain ints have the natural size suggested by the
architecture of the execution environment 44
; the other signed integer types are provided to meet special
needs.

44) ) that is, large enough to contain any value in the range of INT_MIN and INT_MAX, as defined in the header .

Thus
sizeof(short) <= sizeof(int) <= sizeof(long) Thx 2 m$ 4 <= instead of < ;)

14.09.2016

Kategorien von Algorithmen Implementations Muster und Fehler

Filed under: Allgemein — Tags: — Thomas @ 13:09

Mir ist aufgefallen dass die Implementierung von Algorithmen in verschiedene
Kategorien passen. Es geht also nicht um das, was der Algorithmus macht, sondenr
wie er programmiert ist. Die Kategorien sind auch meist Sprach uebergreifend.

Beispiel: segmentTools vertex-collapse

In der derzeitigen Version faellt der Algorithmus in die Kategorie
"korret, aber nicht vollstaendig".
Das bedeutet, das Programm bearbeitet die Probleme richtig, aber nicht fuer alle
Faelle. Es fehlen also einige Sonderfallbehandlungen.

Die Kategorie "Datenabhaenigkeit" ist sehr komplex und oft untergliedert. Fuer den vertex-collaps
Algorithmus gilt, dass ein Segment mit mehreren anderen Segmenten zusammen fallen kann. Also
eine 1-n Beziehung. Momentan wird immernur eine 1-1 Beziehung bearbeitet.
Daher ist die derzeitige Version auch in der Kategorie "nicht vollstaenig". (Gluecklicherweise
kann durch wiederholte Aufrufe des Programms das Problem umgangen werden).

Auch trifft die Kategorie "langsam - quadratisch Laufzeit" zu. Das bedeutet einfach,
dass die Berechnung statt Sekunden (mehrere) Tage dauert.
Dementsprechend gibt es noch die Kategorie "schnell - linear logarithmische Laufzeit".

Um nun den Algorithmen in die Kategorie "schnell" zu heben, gibt es einige schon ausgearbeitet
Techniken. Darum den Sweepline Algorithmus. Dieser steuert, auf einer intelligentere Art und Weise,
welche Segmente der vertex-collapse Algo in welcher Reihenfolge bearbeiten wird. Der Sweepline Algorithmen
bedient sich eines weiteren Algorithmus zum Sortieren von Daten.

Der vertex-collapse Algorithmus faellt also in weitere Kategorien.
Einmal "Datenabhaenigkeit - Reihenfolge". Dadurch entstehen weitere Sonderfaelle welche die 1-n Beziehnung noch
verkomplizieren.

Und es gibt zusaetzliche die Kategoie "Daten Redundanzen/Kopien".
Hier gibt es zwei aehnliche Faelle.

Fall 1:
Um nicht den orignal Datensatz zu veraendern, macht man in der Regel eine Kopie davon und sortiert ihn dann
mit Sweepline. Das funktioniert bei großen Datensatzen nicht mehr, da hier der RAM oft zu klein ist. (Der
Ergebnisdatensatz sollte auch noch in den RAM passen).

Eine gängige Methode um das zu umgehen ist, statt das eigentliche Datenobjekt zu sortieren (das Segment)
werden nur die IDs sortiert. Aber nicht die ID als Nummer, sondern der (speziell hierfuer angepasster) Sortier Algoritmus greift beim
sortieren ueber die ID auf das Segmente Objekt zurueck und erstellt dementsprechend eine Sortierung der IDs.

Das hat Vorteile und auch viele Nachteile.

Vorteile:
* Der Speicherverbrauch sink. Nehmen wir z.B. ein Segment mit zwei 3D Punkten und doppelter Zahlengenauigkeit.
2*3*8byte = 48byte pro Segment. Werden stattdessen nur IDs kopiert und sortiert, fallen nur 4byte pro Segment
zusaetzlich an.
* Die Geschwindigkeit steigt. Im jeder Sortieriteration werden Daten bewegt. Statt 48byte muessen nur 4byte im Ram
bewegt werden.

Nachteile:
* Nicht jeder Datencontainer kann ueber eine integer ID effizient angesprochen werden. Das funktioniert nur effizent
bei Vector Containern. Deque, Hash und Sorted Maps sind auch noch moeglich. Bei Listen funktioniert es nicht mehr.

* Nicht jeder Datencontainer kann ueberhaupt ueber eine integer ID angesprochen werden. Oft werden auch andere Typen
als ID benutzt. Zum Beispiel kurze Strings. Ein Mapping String ID -> Integer ID ist zwar moeglich, kostet aber wieder
Speicherplat und Geschwindigkeit.

* Die ID Variable enthaelt keine Informationen ueber den Datentype auf den sie verweist. Arbeitet man mit mehreren Datensaetze
z.B. Segmente und Punkte, so ist es moeglich mit einer Segment ID Variable auf den Punkt Datensatz zuzugreifen ohne
dass dieser Programmierfehler sofort bemerkt wird.

Fall 2:
Der zweite Fall bezieht sich auf Daten die der Sweepline Algoritmus zwischenspeichert. Auch hier muss wie beim Sortieren
auf die Datenobjekte zugegriffen werden und es entstehen die selben Vor und Nachteile.

Weiterhin muss auch der Sortier Algorithmus darauf hin ausgelegt sein, nicht die eigentlichen Daten zu sortieren, sondern ihre
IDs.
Dies fuehrt zu dem Problem, dass der Programmierer des Sort und auch Sweeplines mit einem unbekannten, benutzer definierten,
Datentype arbeiten muss.
Dies wurde in C und Fortran dadurch geloest, dass der Benutzer definierte Datentype nur als Pointer von Type void (also
keine Type Information), oder noch schlimmer: als Typ double, der Sortier Routine uebergeben wurde. Der Algorithmus arbeitet
also blind aus den Daten und es liegt in der Hoffnung des Programmiers, dass es auch immer funktioniert.

Noch dazu gibt es von C std lib keine Sortierfunktion die zusaetzlich auch IDs beruecksichtigt. Die Routine muss also immer
neu geschrieben werden mit allen Fehlern und Sonderfaelle. Insbesondere bei Fortran. Da es hier nicht mal eine Sortierfunktion
von der Standardlib selbst gibt.

Das Problem mit den benutzer definierten Datentypen wurde mit der Einfuehrung von C++ im Jahre 1984, und die integierte Template
Sprache, geloest.
Es koennen nun abstrakt geschrieben werden und zur Compilierzeit wird der benutzer definierten Datentype eingebaut und entsprechende
Fehler vom Compiler weise auf Probleme hin.

Um die Probleme mit den IDs anzugehen kann man als erstes Versuchen satt einer Integer ID, einen Pointer auf das Datenobjeckt zu speichern
und zu sortieren.

Vorteile:
* Es funktionieren nun alle Containertypen.
* Kein Problem mehr mit string IDs, da auf das Datenobjekt selbst zugegriffen wird.
* Keine extra Mapping sortierte ID -> container -> Datenobjekt mehr noetig
* Weiterhin Platzersparnig als wenn eine Kopie des Objekt sortiert wird

Nachteile:
* Pointer verbrauchen auf 64bit Systemen 8byte, also doppelt so viel wie integer IDs
* Pointer koennen invalid sein. Immer ein Check noetig.
* Pointer muessen immer explizit dereferenziert werden um an das Objekt zu gelanden auf das sie zeigen.

Weiterhin muss der Sortierfunktion eine Funktion uebergeben werden, die besagt, wie zwei Pointer Objeckte auf kleiner "<" verglichen werden konnen. Das ist aber schon immer in C und C++ moeglich. Nur eine Frage der kryptischen Syntax. Um auch die Nachteile der Pointer zu kompensieren, können Referenzen genutzt werden. Vorteil: * Referenzen sind immer valid. * Refreenzen muessen nicht extrea dereferenziert werden. Nachteil: * Referenzen brauchen wie Pointer 8byte. Seit C++ 2011 ist es moeglich auch Referenzen in einem Container zu speichern. Weiterhin gibt es mit Lambdas eine elegante Moeglichkeit die relations Funktion zweite Datenobjekte zu formulieren. Kein kryptischer Code mehr. Somit bietet C++ seit 2011 die fehlerfreiste und performanteste Moeglichkeit einen Algorithmus schneller durch Sortierung zu machen. Viele Worte, wenig Code. So siehts aus:

19.08.2016

Best C++ GC ever!

Filed under: Allgemein — Tags: — Thomas @ 11:08

template< typename T>
T* makeObject() {
  static T* obj = nullptr;
  delete obj;
  obj = new T();
  return obj;
}

02.02.2016

C gecaste (Bug of the day 10)

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

Ist nicht direkt ein Bug, aber kann ganz leicht zu einem werden. Vorallem stört das rum-gecaste und Pointer auf locale Variablen. Hier ein Stück Code, wo ich erst drei mal hinschauen musste


typedef struct s_rocsmq_message {
...
} t_rocsmq_message, *p_rocsmq_message;

void func() {
  t_rocsmq_message message;
  rocsmq_recv(..., (p_rocsmq_message) & message, ROCSMQ_POLL)
}

Aber, ich sollte weniger mich beschweren, ehr Hilfe leisten.
Hier eine sehr einfache C++ version ohne Extras:


namespace rocs{
struct mqMessage {
...
};
}

using namespace rocs;
void func() {
  mqMessage message = mqRecv(...);
}

Keine Pointer, kein gecaste. Lokale Variable dann declariert und gleich initialisiert, wenn man sie braucht.
Projektname "rocs" aus den Datentypen und Funktionsnamen entfernt und in ein namespace ausgelagert. Verständlicher,
weniger Code, weniger Fehler.

26.01.2016

Evaluation of logical operations

Filed under: Allgemein — Tags: , , — Thomas @ 21:01

Spass mit dem Standard.
Aus dem Fortran 90/95 Standard [1] Kapitel 7.1.7.6.

Evaluation of logical intrinsic operations
The rules given in 7.2.4 specify the interpretation of logical intrinsic operations. Once the
interpretation of an expression has been established in accordance with those rules, the processor
may evaluate any other expression that is logically equivalent, provided that the integrity of
parentheses in any expression is not violated.
NOTE 7.29
For example, for the variables L1, L2, and L3 of type logical, the processor may choose to
evaluate the expression
L1 .AND. L2 .AND. L3
as
L1 .AND. (L2 .AND. L3)
Two expressions of type logical are logically equivalent if their values are equal for all possible
values of their primaries.

Aus dem c++11 Standard [2] Kapitel 5.14

logical-and-expression
The && operator groups left-to-right.

Und die andern Operatoren auch left-to-right.

Aus dem C89 Standard [3] Kapitel 3.3

Except as indicated by the syntax27 or otherwise specified later (for the function-call operator () , && , || , ?: , and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.

hf

[1] http://j3-fortran.org/doc/standing/archive/007/97-007r2/pdf/97-007r2.pdf
[2] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
[3] https://web.archive.org/web/20050207005628/http://dev.unicals.com/papers/c89-draft.html#3.3

24.01.2016

Warum (kurze) Arrays in Fortran (und C/C++) nicht immer die richtige Wahl ist

Filed under: Allgemein — Tags: — Thomas @ 22:01

Der Name ist Programm.
Heute mal tex und pdf Version.

wkfanidrwi.pdf

\documentclass[]{article}
\usepackage{listings}
\usepackage[utf8]{inputenc}
\usepackage{ngerman}

%opening
\title{Warum (kurze) Arrays in Fortran (und C/C++) nicht immer die richtige Wahl ist}
\author{Thomas Huxhorn}


\begin{document}

\maketitle

\tableofcontents

\begin{abstract}
In diesem kleinen Artikel lege ich ein paar Gedanken nieder über einen Fehler mit 
(kurzen) Arrays, der systematisch immer wieder Auftritt. Die Wahl der Programmiersprache
ist unabhängig für diese Art von Fehler.
\end{abstract}

\section{Ein Fehler}
Der Fehler selbst lässt sich in einem Satz beschreiben: Einer Funktion wurde nur ein Wert
übergeben, obwohl sie ein Array von zwei Werten erwartet. Das klingt erstmal recht banal, hat es aber in sich.
Hier der entsprechende Beispiel Code in Fortran:

\begin{lstlisting}[frame=single]
subroutine func(data)
  integer, intent(in) :: data(2)
  write(*,*) data(1), data(2)
end subroutine

program test
  integer :: data(2)
  data(1) = 1
  data(2) = 2
  call func(data(1))
end program
\end{lstlisting}

Das Programm compiliert ohne Warnings, ohne Laufzeitfehlermeldungen und keinerlei Überprüfungen die 
der Compiler bereit stellt schlagen Alarm. Sogar die Ausgabe des Programms ist richtig. 
Benutzt wurde der neuste GNU Fortran Compiler in der Version 5.2.1

\begin{lstlisting}[frame=single]
$ gfortran -Wall -Wextra -fcheck=all 
-fsanitize=address,undefined wkfanidrwi1.f95
$ ./a.out 
1           2
\end{lstlisting}

\section{Ein unsichtbarer Fehler}
Auch der memory error detector valgrind findet keinerlei Fehler. Der Grund ist ganz einfach: Aus technischer
Sicht existiert in diesem Programm auch kein Fehler! Das ist auf den ersten Blick etwas verwirrend. 
Der Programmierer wollte, dass die Subroutine func() nur die erste Zahl im Array data verarbeitet. Die Subroutine 
hingegen, erwartet nicht nur zwei Zahlen, sie nimmt sich auch zwei Zahlen! Selbst, wenn man ihr nur eine gibt.
Wir haben hier also gleichzeitig zwei Arten von Fehler. Der Programmierer hat eine Vorstellung, was passieren soll.
Seine Kenntnis über die Subroutine func ist aber falsch, so dass er zu wenig Daten übergibt. Das ist der erste Fehler.
Der zweite Fehler ist, dass der Programmierer die Subroutine so erstellt hat, dass sie immer genau so viele Daten
verarbeitet, wie sie braucht. Egal ob sie auch genügend Daten bekommt. Die beiden Fehler heben sich gegenseitig auf,
und es kommt auch das richtige Ergebnis raus. Kein Programm kann den Fehler finden.

\section{Ein versteckter Fehler}
Heutzutage sind Programme riesig. Sie bestehen aus einer Millionen Zeilen Code, sind über Jahrzehnte gewachsen und kein
Mensch blickt mehr in allen Details durch. Diese Art Fehler zu erkennen ist also menschlich nicht möglich. Ein 
Computer Programm könnte es aber. Der Compiler sieht beim Compilieren das gesamte Programm, den kompletten Quellcode.
Man muss den Compiler aber auch seine Arbeit tun lassen, und nicht selbst die Arraygröße bestimmen.

\section{Lösungversuch}
Die erste Idee ist also, das die Subroutine nicht ein Array fester Größe, sondern eins variabler Größe erwartet. So kann zur
Laufzeit erkannt werden, ob zu viele oder zu wenige Daten übergeben wurden. Hier eine Beispiel Implementierung.

\begin{lstlisting}[frame=single]
module testmodule
contains
subroutine func(data)
integer, intent(in) :: data(:)
write(*,*) data(1), data(2)
end subroutine
end module

program test
use testmodule
integer :: data(2)
data(1) = 1
data(2) = 2
call func(data(1))
! call func(data(1:1))
end program
\end{lstlisting}

Sie Subroutine muss dazu in ein Modul gepackt werden, sonst können keine assumed-shape Arrays benutzt werden.

\begin{lstlisting}[frame=single]
$ gfortran -Wall -Wextra -fcheck=all wkfanidrwi1.f95
wkfanidrwi2.f95:14:12:

call func(data(1))
1
Error: Rank mismatch in argument 'data' at (1) 
(rank-1 and scalar)
\end{lstlisting}

Schon allein das Compilieren führt hier zu einem Fehler. Aber nur, weil ein Array erwartet, aber ein Skalar übergeben wurde. Das kann man ganz leicht aus tricksen, in dem man ein Array der Länge 1 übergibt. Dieser Fall wird dann, wie
erwartet, zur Laufzeit abgefangen.

\begin{lstlisting}[frame=single]
$ ./a.out 
At line 5 of file wkfanidrwi2.f95
Fortran runtime error: Index '2' of dimension 1 of array
'data' above upper bound of 1
\end{lstlisting}

Der Fehler wird jetzt zur Laufzeit erkannt. Das ist schon einmal ein riesiger Fortschritt, als wenn der Fehler nie erkannt wird. Allerdings muss nun bei jedem Array Zugriff die Länge des Arrays überprüft werden. Im Durchschnitt verdoppelt das die Laufzeit des Programms. Und der Fehler wird auch nur gemeldet, wenn entsprechende Checks im
Compiler eingeschaltet wurden. \\
Können wir das nicht besser machen? Immerhin WISSEN wir ja, wie viele Daten die Subroutine brauch. Das muss sich
ausnutzen lassen.

\section{Lösung allgemein}
Die allgemeine Lösung für diese Art von Fehler besteht darin, einfach keine Arrays für so wenige Daten zu nutzen.
Um dennoch nicht jede einzelne Zahl als Parameter zu übergeben, und damit den Code unnötig groß zu machen,
werden die Daten in einem neuen Datentyp gruppiert. \\
Da der Datentyp zwangsläufig einen Namen braucht, können wir den Variablen gleichzeitig eine Bedeutung geben. So ist
ein weiterer Fehler ausgeschlossen, dass man z.B. aus versehen data(1) statt data(2) benutzt.
Hier die Beispiel Implementierung:

\begin{lstlisting}[frame=single]
module testmodule
type Uhrzeit_t
integer :: minute, stunde
end type
contains
subroutine func(uhrzeit)
type(Uhrzeit_t), intent(in) :: uhrzeit
write(*,*) uhrzeit%stunde, uhrzeit%minute
end subroutine
end module

program test
use testmodule
type(Uhrzeit_t) :: uhrzeit
uhrzeit%minute = 1
uhrzeit%stunde = 2
call func(uhrzeit)
end program
\end{lstlisting}

Der ursprüngliche Fehler ist nun nicht mehr möglich. Unnötig Laufzeiteinverschlechterungen sind auch nicht mehr vorhanden. Der Compiler kann durch Typenüberprüfungen zur Compilezeit feststellen, ob die Subroutine immer den
richtigen Datentype erhält. \\

\section{Ausblick}
So weit so gut. Mit der Implementierung dem Uhrzeit Modul haben wir aber viele weitere Fehlerquellen erschaffen.
In der Praxis reicht es nicht einfach nur Stunde und Minute auszugeben. Datum und Uhrzeit müssen verglichen, umgerechnet, verrechnet und erstellt werden. Für all das existieren schon fertige Module, teilweise standardisierte und alle getestet. 


\section{Lösung Qt}

Qt bietet hierfür die Klasse QTime an.
Hier ein Beispiel wie ein Zeitobjekt erstellt, einer Funktion
übergeben und ausgegeben wird.

\begin{lstlisting}[frame=single]
void func(QTime time) {
	qDebug() << time.toString();
}

QTime time(1,2);
func(time);
\end{lstlisting}

QTime selbst ist eine Klasse welche nicht nur Stunden, Minuten, Sekunden
und Millisekunden speichern kann. Sondern auch die Textausgabe im
jeweiligen Landesformat übernimmt und mit der Klasse QDateTime werden
auch Winter und Sommerzeit beachtet.

\section{Technische Details des Fehlers}
Wie am Anfang erwähnt ist diese Fehlerart unabhängig der gewählten
Programmiersprache. Auch in C können Arrays als Funktions Parameter
eine feste Länge zugewiesen werden. Und da C++ rückwärts kompatibel
zu C ist, ist der Fehler auch in C++ machbar. Es hängt nicht von der 
Sprache ab, sondern die Art wie man programmiert. \\
In der Subroutine wurde ein Array fester Länge angegeben. Damit 
existiert das Array für den Compiler! und er würde so nie einen
Fehler finden. Warum die ganzen Memory Check Programm auch keinen
Fehler finden, ist recht einfach. Es existiert im Programm ja auch
ein Array richtiger Länge. Es wurde nur ein statt zwei Elemente 
übergeben. Aber in dem Moment wo in der Subroutine auf das
zweite Element zugegriffen wird, wird gültiger Speicher ausgelesen.

\end{document}


14.01.2016

std::normal_distribution

Filed under: Allgemein — Tags: — Thomas @ 16:01

Wie baut man aus gleichverteilen Zufallszahlen normalverteile?
Man nimmt std::normal_distribution

http://en.cppreference.com/w/cpp/numeric/random/normal_distribution

Und wie ist das Implementiert? Eine Beispielimplementation gibt es in der gnu stdc++

https://gcc.gnu.org/onlinedocs/gcc-4.7.4/libstdc++/api/a01267_source.html#l01678

Wtf? Versteht kein Mesch. Das Paper auf dass die sich beziehen ist auch ein Hammer.

http://www.eirene.de/Devroye.pdf Seite 249

Hier die Template bereinigte Version vom GNU


#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>

double round(double x) {
    return int(x*10)/10.0;
}

// erzeugt gleichverteilte zufallzahlen im interfall [0:1]
struct uniform_real_random_device {
    std::mt19937 gen;
    std::uniform_real_distribution<> uniform_dist = std::uniform_real_distribution<>(0.0, 1.0);

    double operator() () {
        return uniform_dist(gen);
    }
};

/**
  * Polar method due to Marsaglia.
  *
  * Devroye, L. Non-Uniform Random Variates Generation. Springer-Verlag,
  * New York, 1986, Ch. V, Sect. 4.4.
  *
  * https://gcc.gnu.org/onlinedocs/gcc-4.7.4/libstdc++/api/a01267_source.html#l01678
  */
double normal_dist(uniform_real_random_device& rand, double mean, double stddev) {
    double x, y, r2;
    do
    {
        x = 2.0 * rand() - 1.0;
        y = 2.0 * rand() - 1.0;
        r2 = x * x + y * y;
    }
    while (r2 > 1.0 || r2 == 0.0);

    double mult = std::sqrt(-2 * std::log(r2) / r2);
    double result = y * mult;
    result = result*stddev + mean;
    return result;
}

int main() {
    uniform_real_random_device uniformRand;

    std::map hist;
    for(int n=0; n<100000; ++n) {
        double gaussZahle = normal_dist(uniformRand, 0.5, 0.5);
        ++hist[round(gaussZahle)];
    }

    // ausgabe
    for(auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/100, '*') << '\n';
    }
}

-1.5
-1.4
-1.3
-1.2
-1.1
-1.0
-0.9 *
-0.8 *
-0.7 ***
-0.6 *****
-0.5 ********
-0.4 ************
-0.3 ******************
-0.2 **************************
-0.1 **********************************
0.0 ************************************************************************************************
0.1 **************************************************************
0.2 *********************************************************************
0.3 ****************************************************************************
0.4 *******************************************************************************
0.5 *******************************************************************************
0.6 ****************************************************************************
0.7 **********************************************************************
0.8 *************************************************************
0.9 *****************************************************
1.0 *******************************************
1.1 **********************************
1.2 **************************
1.3 ******************
1.4 *************
1.5 *********
1.6 *****
1.7 ***
1.8 **
1.9 *
2.0
2.1
2.2
2.3
2.4
2.5

Jaaa da ist noch ein Bug drin bei der 0. Wer ihn findet, darf mir eine Mail schreiben.

03.01.2016

XKCD 1188 BOUNDING

Filed under: Allgemein — Tags: — Thomas @ 22:01

http://xkcd.com/1188/

Lame Segfault.


#include <exception>
using namespace std;
struct Ball : public exception {
};

struct P {
  P* target;
  void aim(const Ball& ball) {
    try {
      throw ball;
    }
    catch(Ball& ball) {
      target->aim(ball);
    }    
  }
};

int main() {
  P parent;
  P child{&parent};
  parent.target = &child;
  parent.aim(Ball());
}
« Newer PostsOlder Posts »

Powered by WordPress