C++Guns – RoboBlog blogging the bot

29.01.2016

Programm Environment Modules

Filed under: Allgemein — Thomas @ 16:01

touch

dpkg -l | grep tcl
ii  libtcl8.5:amd64                        8.5.17-1                             amd64        Tcl (the Tool Command Language) v8.5 - run-time library files
ii  libtcl8.6:amd64                        8.6.2+dfsg-2                         amd64        Tcl (the Tool Command Language) v8.6 - run-time library files
ii  tcl                                    8.6.0+8                              amd64        Tool Command Language (default version) - shell
ii  tcl-dev:amd64                          8.6.0+8                              amd64        Tool Command Language (default version) - development files
ii  tcl8.5                                 8.5.17-1                             amd64        Tcl (the Tool Command Language) v8.5 - shell
ii  tcl8.5-dev:amd64                       8.5.17-1                             amd64        Tcl (the Tool Command Language) v8.5 - development files
ii  tcl8.6                                 8.6.2+dfsg-2                         amd64        Tcl (the Tool Command Language) v8.6 - shell
ii  tcl8.6-dev:amd64                       8.6.2+dfsg-2                         amd64        Tcl (the Tool Command Language) v8.6 - development files
ii  tclx8.4                                8.4.1-1                              amd64        Extended Tcl (TclX) - shared library
ii  tclx8.4-dev                            8.4.1-1                              amd64        Extended Tcl (TclX) - development package


 touch .spec.in
CPPFLAGS="-DUSE_INTERP_ERRORLINE" ./configure --with-tclx-lib=/usr/lib/ --with-tclx-inc=/usr/include/tclx8.4/ --with-tclx-ver=8.4

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}


21.01.2016

template loop mit rekursion

Filed under: Allgemein — Thomas @ 09:01

Einfache Schleifen mit Templates funktionieren mittels Rekursionen. Das ist auf
dem ersten Blick etwas ungewöhnlich, aber letzendlich doch nur eine Schleife.
Wir muessen die Anzahl an Iterationen aber zur Compilezeit vorgeben! Entweder
per Template Parameter oder constexpr.

Normal würde man Parameterlisten packen/unpacken oder was man sonst in einer Schleife macht.
Ich möchte aber N mal eine Funktion mit einem laufenden Template Parameter i erstellen.
Erstens kann ich so meine Funktion für ein festes N specialisieren, zweitens kann man
die spezielle Funktion zur Laufzeit auswählen.


#include <iostream>
#include <array>

template<int N>
void funcToImpl(int n) {
  std::cout << "template N: " << N << " runtime n: " << n < fixedLengthArray;
}

template<int i>
void func(int n) {
  if(i == n) {
    funcToImpl(n);
  } else {
    func<i-1>(n);
  }
}

// rekursionsanker bei i=0
template<>
void func<0>(int n) {
  funcToImpl<0>(n);
}

int main(int argc) {
  // rekursion faengt bei i=80 an
  func<80>(argc);
}

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());
}

01.01.2016

rvalues, lvalues, xvalues, glvalues, prvalues WTF??

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

Sehr zu empfehlen:
http://www.stroustrup.com/terminology.pdf


int   prvalue();
int&  lvalue();
int&& xvalue();

void foo(int&& t) {
  // t is initialized with an rvalue expression
  // but is actually an lvalue expression itself
}

GNhBF

— An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [ Example: If E is an expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue. —end example ]

— An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ]

— A glvalue (“generalized” lvalue) is an lvalue or an xvalue.

— An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expressions) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

— A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [ Example: The result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. —end example ]

Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue, or prvalue. This property of an expression is called its value category. [ Note: The discussion of each built-in operator in Clause 5 indicates the category of the value it yields and the value categories of the operands it expects. For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types. —end note

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3055.pdf
http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues

Powered by WordPress