C++Guns – RoboBlog blogging the bot

12.09.2014

Python Naming Conventions

Filed under: Allgemein — Thomas @ 09:09

The naming conventions of Python's library are a bit of a mess, so we'll never get this completely consistent

http://legacy.python.org/dev/peps/pep-0008/

Python ist SCHROTT ;)

I can feel segfaults

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

int main() {
  const char *a = "I can feel segfaults";
  printf("%c\n", (char*) * (char*) * (a+strlen(a)));
  return 0;
}

04.09.2014

virtual inheritance and sizeof()

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

Folgender Code:


#include < iostream >
#include < stdint.h >

using namespace std;

class Base {
   public:
   int32_t a;
};

class Derived :  public Base {
public:
  int32_t b;
};

class VirtualDerived : virtual  public Base {
public:
  int32_t c;
};

int main() {
  cout << "sizeof Base " << sizeof(Base) << "\n";
  cout << "sizeof Derived " << sizeof(Derived) << "\n";
  cout << "sizeof VirtualDerived " << sizeof(VirtualDerived) << "\n";

  return 0;
}

ergibt auf einer 32Bit Maschine folgende Ausgabe

sizeof Base 4
sizeof Derived 8
sizeof VirtualDerived 12

Die Größe der VirtualDerived Klasse ist also nicht einfach die Summer zweier 4Byte Variablen, sondern auch noch zusätzlich ein 4Byte Pointer auf die Base Klasse.

Auf einer 64Bit Maschine sind es entsprechend 16Byte

sizeof Base 4
sizeof Derived 8
sizeof VirtualDerived 16

03.09.2014

Fortran is DEAD!!

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

Leute, ist sag es schon die ganze Zeit: Fortran ist eine tote Sprache.
Und damit meine ich nicht nur diese verbuggten Compiler. Oder dass es ewig braucht bis man ein neues Feature vom Compiler unterstützt wird. Im Fortran 2003 Standard sind zwar schön viele OO Ansatze festgelegt, aber ich kenne kein Compiler der den Standard nach 10 Jahre komplett unterstützt. Andere Sprachen sind schon 2 Schritte weiter.

Nein, diesmal habe ich viel bessere Argumente auf Lager. In dem Paper [1] wurden 800000 Software Projekte und 13000 Programmierer ausgewertet. Ich möchte nur zu einem Bild aus diesem Paper meine Meinung loswerden. Dieses da:

languages

Also, man sieht hier die Wahrscheinlichkeit, mit der man die Programmiersprache wechselt, wenn ein neues Projekt angefangen wird. Weis bis blau sind niedrige Wahrscheinlichkeiten und rot bis schwarz hohe.
Die Punkte auf der Diagonalen zeigen, dass man die Sprache NICHT wechselt.
Was haben wir denn da alles:
Rote Punkte sehe ich bei allesn *Basic Sprachen. Auch bei der C-Familie mit Java, Perl, PHP, Python bleiben die Programmierer bei ihrer Sprache.

Welche Sprachen bekommen Zuwachs? Das sieht man schön an den vertikalen Balken. Also Java, C/C++ und meinetwegen noch PHP. Das sind also die view Großen wohin die Programmierer wechseln, nachdem sie erkannten, dass ihre vorherige Wahl Schrott war. Tja, wagt es nicht das Wort gegen C++ zu erheben ;) Die Sprache ist sowas von geil und wird den ganzen anderen Schrott längerfristig schon tot trampeln ;)

Wohin rennen denn die Fortran Leute? JAVA. Ach ich lach mich kaputt. Das sind doch total verschiedene Welten.
Ich wette die Auftraggeber wollten parallelisierte hoch performante Software. Haben aber keine Programmierer gefunden der was aufn Kasten hat, und der Rest kam mit der Sprache nicht klar. Also wurde es wieder Java. Das ist ja bekannt und jeder kann es. Und jetzt ärgern die sich mit ihrere total aufgeblasenen, lahmen Software rum, HäHä.

Die *Basic sprachen sind auch alle hinfällig. Zwar wechseln die Leute hier nicht, aber es kommen auch keine neuen hinzu. Die Sprache stirbt also aus, wenn auch alle *Basic Programmierer ausgestorben sind. Sehr einfach Das ;)

[1] Empirical Analysis of Programming Language Adoption; Leo A. Meyerovich; Ariel S. Rabkin

01.09.2014

Fortran progressmeter nice code

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



! use modulo to determine when to print progress
! not independet of called algorithm speed
! possible output:
! 0.0  % done
! 0.01 % done
! 0,02 % done
! 0,03 % done
! or only one output
! 80.0 % done
! We can do better!
subroutine variant1(n)
  implicit none
  integer, intent(in) :: n
  integer :: i
  
  do i=1, n
    if(mod(i, 1000) == 0) write(*,*) 100.0*i/n, "% done"
    
    ! call some algorithm
    ! ...
  end do
end subroutine

! check in every iteration if progress is 10%, 20% u.s.w.
! pro: independet of called algorithm speed
! contra: more code
! possible output:
! 10 % done
! 20 % done
! 30 % done
! 80 % done
! 90 % done
! We can do better!
subroutine variant2(n)
  implicit none
  integer, intent(in) :: n
  integer :: i
  real :: percent, thr
  
  thr = 1.0 / n * 100.0  
  do i=1, n
    percent = 100.0*i/n
    if(percent > 10.0 .and. percent < 10.0+thr) write(*,*) "10 % done"
    if(percent > 20.0 .and. percent < 20.0+thr) write(*,*) "20 % done"
    if(percent > 30.0 .and. percent < 30.0+thr) write(*,*) "30 % done"
    if(percent > 40.0 .and. percent < 40.0+thr) write(*,*) "40 % done"
    if(percent > 50.0 .and. percent < 50.0+thr) write(*,*) "50 % done"
    if(percent > 60.0 .and. percent < 60.0+thr) write(*,*) "60 % done"
    if(percent > 70.0 .and. percent < 70.0+thr) write(*,*) "70 % done"
    if(percent > 80.0 .and. percent < 80.0+thr) write(*,*) "80 % done"
    if(percent > 90.0 .and. percent < 90.0+thr) write(*,*) "90 % done"      
    
    ! call some algorithm
    ! ...
  end do
end subroutine

! recalc threshold in every iteration
! possible output:
! 10 % done
! 20 % done
! 30 % done
! ...
! 90 % done
! almost done!
! we have to avoid duplicate code; copy&paste erros
subroutine variant3(n)
  implicit none
  integer, intent(in) :: n
  integer :: i
  real :: percent
  integer :: thr
  
  thr = 10
  do i=1, n
    percent = 100.0*i/n
    if(percent > thr) then
      write(*,*) thr, "% done"
      thr = thr +  10
    endif
    
    ! call some algorithm
    ! ...
  end do
end subroutine


! to avoid duplicate code and copy&paste errors, we move the code into a class and provide a progress function as interface
module ProgressMeterClass
  implicit none
  private
  public :: createProgressMeter

  type, public :: ProgressMeter
      integer, private :: n
      integer, private :: thr
    contains

      procedure :: progress
  end type
  
  interface createProgressMeter
    module procedure newProgressMeter
  end interface

  contains

  function newProgressMeter(n) result(this)
    implicit none
    type(ProgressMeter) :: this
    integer, intent(in) :: n

    this%n = n
    this%thr = 10
  end function

  subroutine progress(this, i)
    implicit none
    class(ProgressMeter), intent(inout) :: this
    integer, intent(in) :: i

    if(100.0*i/this%n > this%thr) then
      write(*,*) this%thr, "% done"
      this%thr = this%thr + 10
    endif
  end subroutine
end module


!> we use OO techniques. The progressmeter code is now in the ProgressMeterClass module.
!> We simply create an object of this type and call progress() on it in every iteration
subroutine variant4(n)
  use ProgressMeterClass
  implicit none
  integer, intent(in) :: n
  integer :: i
  type(ProgressMeter) :: pm
  
  ! we can pass a step and filehandle variable too
  pm = createProgressMeter(n)
  do i=1, n
    call pm%progress(i)
    
    ! call some algorithm
    ! ...
  end do
end subroutine

program Progressmeter  
  implicit none
  integer :: n

  n = 10000000

!   call variant1(n)
!   call variant2(n)  
!   call variant3(n)  
  call variant4(n)  
end program

15.08.2014

polymorphic objects can live on the stack

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

Polymorphie kennt ihr ja, Grundzüge von OO;
Im groben geht das ja so


class Base {
  public:
  virtual void func() {
     cout << "Base\n";
  }  
};

class Derived : public Base {
  public:
  virtual void func() {
    cout << "Derived\n";
  }  
};

int main() {
  Base *p = new Derived();
  p->func();  // print "Derived"
}

Ich habe ein Pointer vom Type Base und dennoch wird die Funktion von Derived aufgerufen.
Das hier funktioniert allerdings auch:


int main() {  
  // We dont need to create the object on the heap with new
  // Base *p = new Derived();
  
  // Allocate this object on the stack
  Derived d;   
  Base *p = &d;
  p->func(); // prints "Derived" and not "Base"
}

Objekte auf dem Stack werden wesentlich schneller allokiert als auf dem Heap. Das müsste ein deutlichen Geschwindigkeitsvorteil für kleine und kurzlebende Objekte sein.

26.07.2014

Fortran Speicherverbraucht ermitteln

Filed under: Allgemein — Tags: , — Thomas @ 13:07

Wieviel Speicher verbraucht mein Programm? Die Frage ist nicht so einfach zu beantworten, denn es gibt kein Funktionsaufruf in C der bei jedem Compiler und jedem *unix funktioniert. Nach vielen googlen habe ich herausgefunden, dass es wohl am besten ist, die entsprechenden Datein in /proc zu parsen.

In /proc/self/status steht unter anderem auch der Speicherverbraucht dinne. Man kann auch /proc/self/statsm parsen, wenn man Lust hat.

kater@mintux:~$ gfortran -Wall -o procstat procstatus.F90
kater@mintux:~$ ./a.out 
 VM size:        43044  kB

Das komplette Programm ist im Anhang.
procstatus.F90

24.07.2014

Welcher Code ist "schöner" ? ;)

Filed under: Allgemein — Tags: , — Thomas @ 14:07

Kurzes Programm, welches überpüft ob der Benutzer eine Variable "resolution" definiert hat. Wenn ja, wird versucht die Benutzereingabe in eine Zahl umzuwandeln. Wenn nein, wird ein default Wert von 1 angenommen.

Variante 1:


const QString resolution = options().text("resolution");
bool userResolution = false;
// check if user defined cellsize
qreal newCellSize = 1;
if(!resolution.isEmpty()) {            
  userResolution = true;
  bool ok;
  const qreal userCellSize = resolution.toDouble(&ok);
  if(ok) {
    newCellSize = userCellSize;
  }
  else {
    qDebug() << "Cant parse user defined resolution:" << resolution;
  }
}

Die Variable userResoltion ist nicht als const declariert und könnte überschrieben werden. Machen wir sie read-only!

Variante 2:


const QString resolution = options().text("resolution");
const bool userResolution = !resolution.isEmpty();
// check if user defined cellsize
qreal newCellSize = 1;
if(!resolution.isEmpty()) {            
  bool ok;
  const qreal userCellSize = resolution.toDouble(&ok);
  if(ok) {
    newCellSize = userCellSize;
  }
  else {
    qDebug() << "Cant parse user defined resolution:" << resolution;
  }
}

Der Code sieht noch etwas aufgebläht aus. Trennen wir den normalen Programm Path und den Error Path, der durchlaufen wird, wenn die Benutzereingabe ungültig ist.

Variante 3:


qreal toDouble(const QString& s) throw(Exception) {
    bool ok;
    qreal x = s.toDouble(&ok);
    if(!ok)
        throw Exception("Cant convert to double" + s);
    return x;
}

...

const QString resolution = options().text("resolution");
const bool userResolution = !resolution.isEmpty();
// check if user defined cellsize
qreal newCellSize;
try {
      newCellSize = toDouble(resolution);
}catch(...) {
      newCellSize = 1.0;
      if(!resolution.isEmpty())
           qDebug() << "Cant parse user defined resolution:" << resolution;
}

Nun möchten wir die Variable newCellSize auch noch read-only haben, da sie ein Parameter ist und niemals mehr geändert werden darf. Dafür lagern wir nun die komplette Logik für das Parser der Benutzereingabe in eine Funktion aus.

Variante 4:


qreal toDouble(const QString& s, qreal defaultValue = 0.0) {
    if(s.isEmpty())
        return defaultValue;

    bool ok;
    qreal x = s.toDouble(&ok);
    if(!ok) {
        qDebug() << "Cant convert to double" + s;
        return defaultValue;
    }
    return x;
}

...

const QString resolution = options().text("resolution");
const bool userResolution = !resolution.isEmpty();
// check if user defined cellsize
const qreal newCellSize = toDouble(resolution, 1.0);

Der wesentliche Code ist jetzt nur noch 4 Zeilen lang, statt 15 Zeilen.
Er ist auf das wesentliche reduziert, verständlicher und gegen das versehentliche überschreiben der Variablen geschützt.
Nachteile gibt es allerdings auch. Die Fehlermeldung wenn das Konvertieren fehl schläng ist nicht anpassbar. Mit einem zustäzlichen Funktionsargument könnte man das aber nachbessern.

23.07.2014

SSH Tunnels

Filed under: Allgemein — Tags: — Thomas @ 14:07

local$ ssh -4 -p PORT -N -L 8000:192.168.210.102:80 user@ite

Nette Sache Das! SSH bindet aber leider keine Ports an 0.0.0.0 da muss man mit netcat etwas nachhelfen
01.2018 Update: Doch das geht. Man muss nur 0.0.0.0: vorne dran setzen. Für IPv4 natürlich.
02.2019 Update2: Für IPv4 die -4 nicht vergessen. Sonst bind [::1]:10000: Cannot assign requested address

Old:
local$ ssh -p PORT -L 1391:192.168.210:41:139 user@ite -N
local$ netcat -l -p 139 -c "netcat 127.0.0.1 1391"

Mit 445 genauso.

28.05.2014

Qt - Approximate median without sort / storing an extra copy of the data

Filed under: Allgemein — Tags: , — Thomas @ 20:05

Es gibt viele Möglichkeiten den Median zu berechnen. Eine wäre die Daten zu sortieren und dann das mittlere Element zu wählen.
Dazu muss man aber eine Kopie der Daten speichern, was ungünstig ist, wenn der Arbeitsspeicher schon fast voll ist. Jaaa, heutzutage hat jeder Unmengen an Arbeitsspeicher. Es gibt aber Menschen die haben "NUR" 2GB RAM und die sind durch die aufgeblasenen Standardprogramme (Browser, Office, Mail, Clould, Solzial) schon zu 85% belegt. Und wenn man dann noch etwas Arbeiten will und sich ein paar Datensätze visualisiert, können schon 50MB mehr zum Überlaufen des RAMs führen ;)

(50MB entsprechen ca. 7Millionen double Variabeln)

Es wäre doch toll, wenn man den Median berechnen könnte, ohne den Datensatz zu verändern oder zu kopieren!

Eine Runde googlen:
http://stackoverflow.com/questions/638030/how-to-calculate-or-approximate-the-median-of-a-list-without-storing-the-list/638713#638713

Ich hab diesen Algorithmus mal in Qt implementiert und ein wenig verändert. Bei einer grade Anzahl von Eingangsdaten berechnet er ursprüngliche Algorithmus den falschen Median. Ich habe es jetzt so geändert, dass immer das oberste der beiden mittleren Elemente im Array zurückgegeben wird. Das kann man irgendwann auch noch mal verbessern.

Noch ein Wort zur Laufzeit. Die Anzahl der Iterationen betrug bei meinem Tests meist so um die 50. Das muss eigentlich auch so sein, denn wir haben es hier mit einer binären Suche zu tun. Denn bei jeder Iteration wird der Zahlenbereich, der mit einer double precision floating number Variable dargestellt werden kann, in 2 Hälften zerlegt. So tanzt der approximierte Median immer um den echten Median herrum, bis die Zahlengenauigkeit fein genug ist.
Mit double Precision bekommt man etwa 16 Ziffern Genauigkeit. Und der 2er Logarithmus von 50 ergibt eine Zahl mit 16 Ziffern. Das passt doch :D Man muss also immer 50mal den Zahlenbereich aufteilen um an den Median zu kommen.

Bei jeder dritten Iteration bekommt man also etwa eine Ziffer an Zahlengenauigkeit dazu. Gibt man sich mit nur 8 Ziffern Genauigkeit zufrieden, braucht man auch nur 25 Iterationen.

Wir haben also einen Agorithmus dessen Laufzeit linear mit der größe des Datensatzes wächst O(n*50). Das ist doch super! Ganz anders als die Variante welches erst die Daten sortiert O(n*log(n)). In der Praxis bringt einem das aber erstmal nichts an Laufzeit. Denn wie groß muss der Datensatz werden, damit der log(n) = 50 wird? 1,125,899,906,842,624 ! Also erst ab einer Billiarden Zahlen hätten wir ein Laufzeitvorteil. Dazu bräuchte man aber auch 8000 Terrabyte an Speicherplatz :D

Gibt man sich in Qt/C++ eine Zahl in der Konsole aus, bekommt man in der Regel nur 6 Ziffern angezeigt. Das entspricht 18Iterationen. Also log(n) = 18 für n = 262,144 Hier sieht die Welt schon besser aus. Schon ab 260,000 Zahlen bekomen wir ein Laufzeitvorteil.

Wir haben also ein Algorithmus, der keinen zusätzlichen Speicherplatz braucht und auch noch in der Laufzeit einstellbar ist. Gibt man sich nur mit wenigen relevanten Ziffern des approximierten Medians zufrieden, ist die Laufzeit schon bei kleinen Datenmengen besser als die des Sortierverfahrens.

Happy coding ;)


/*
Find Min and Max of the list containing N items through linear search and name them as HighValue and LowValue Let MedianIndex = floor(N/2)

1st Order Binary Search:

Repeat the following 4 steps until LowValue < HighValue.

    Get MedianValue approximately = ( HighValue + LowValue ) / 2

    Get NumberOfItemsWhichAreLessThanorEqualToMedianValue = K

    is K > MedianIndex ? then HighValue = MedianValue Else LowValue = MedianValue


  */
/*!
  Return the median. If data has even size, not the avg of the two numbers in the
  middel of the array is returned, but the upper one.

  This is an improved version from
  http://stackoverflow.com/questions/638030/how-to-calculate-or-approximate-the-median-of-a-list-without-storing-the-list/638713#638713

  This algorithm need in practice 50 iterations. Like a binary search around the true median.
  */
qreal experimenalMedian(const QVector &data) {
    if(data.isEmpty())
        return 0.0;

    QPair minmax = qMinMax(data);
    int medianIdx = qFloor(data.size()/2.0);
    qreal medianValue = (minmax.first + minmax.second)/2.0;

    while(minmax.first < minmax.second &&
          !fuzzyCompare(minmax.first, minmax.second)) {
        medianValue = (minmax.first + minmax.second)/2.0;
        int K = 0;
        for(int i=0; i < data.size(); i++) {
            if(data.at(i) <= medianValue) {
                K++;
            }
        }
        K > medianIdx ? minmax.second = medianValue : minmax.first = medianValue;
    }
    return medianValue;
}


« Newer PostsOlder Posts »

Powered by WordPress