C++Guns – RoboBlog blogging the bot

02.01.2015

raw speed of C using OO with C++

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

Programs written in C are very very fast. Those written in C++ can be slower due to the fact that copying object is not alway easy as copying an array of numbers. One have to call the copy constructor maybe with side effects like allocate some space.

The language C++ is full backwards compatible to C. So what must we do to use classes and objects with the copy speed of C?

First of all, in C there exist so called POD (plan old data) types like integers, floating point numbers as well as structs und unions. The C language have no class keyword. But classes in C++ can be POD too under certain circumstances. What exactly we need to get a class POD can be read in the C++11 Standard or under [1].
The great benefit of POD types is that it can be copied by simply moving bytes in RAM from one location to another. No call to constructors is needed. That speed up copying enormously.

Enough theory, lets build our own object oriented POD class!
Let's start with a simple class Point that represent a point in 2D. We want to construct a Point object by passing its x and y coordinate. We also want some getter and setter for the coordinates to make the member variables private.

Here is our first implementation:


#include < iostream >
#include < type_traits >

class Point {
public:
  Point() : x(0), y(0) {}
  Point(double x, double y) : x(x), y(y) {}

  void setX(double x) { this->x = x; }
  void setY(double y) { this->y = y; }
  double getX() const { return x; }
  double getY() const { return y; }

private:
  double x, y;
};

int main() {
  Point p(1,2);
  Point p2;

  std::cout << p.getX() << " " << p.getY() << std::endl;

  return 0;
}

Pretty straight forward, right? Save it under point.cpp and compile it with:

$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp 
$ ./a.out 
1 2

I use as compiler gnu g++ version 4.7 to test backwards compatibility. Current is 4.9.2 and 5.0 will be released soon. But you can use any compiler as long it supports c++11. Except for g++ 4.6 thats too old.

To test of a type id POD c++11 provides a simple test [2] which is defined in header file "type_traits". Add this line to our main() function, recompile and run again


std::cout << std::boolalpha;
std::cout << "Point is POD " << std::is_pod::value << "\n";
$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp 
$ ./a.out
1 2
Point is POD false

This shouldn't be too much surprising. As mentioned earlier there are strict rules for when a type is POD. For example the class must be a TrivialType [3]. We can test with is_trivial().


std::cout << "Point is TrivialType " << std::is_trivial::value << "\n";
$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp 
$ ./a.out
1 2
Point is POD false
Point is trivial false

A TrivialType in turn must be TriviallyCopyable [4] and must have Trivial default constructor [5]. Lets test these:


std::cout << "Point is TriviallyCopyable " << std::is_trivially_copyable::value << "\n";
std::cout << "Point is trivially default-constructible " << std::is_trivially_default_constructible::value << "\n";

...

Unfortunately g++ 4.9 does not implement these tests. So we have to wait for version 5.
Instead we can have a closer look about what a "Trivial default constructor" is.

The default constructor for class T is trivial (i.e. performs no action) if all of the following is true:

  • The constructor is not user-provided (that is, implicitly-defined or defaulted)
  • T has no virtual member functions
  • T has no virtual base classes
  • T has no non-static members with brace-or-equal initializers
  • Every direct base of T has a trivial default constructor
  • Every non-static member of class type has a trivial default constructor
  • Right the first condition does not hold. We provide a user default constructor which simply set x and y to zero. Lets remove this constructor and see whats happen:

    $ g++-4.7 -Wall -Wextra -std=c++11 point.cpp 
    point.cpp: In function ‘int main()’:
    point.cpp:20:9: error: no matching function for call to ‘Point::Point()’
    point.cpp:20:9: note: candidates are:
    point.cpp:7:3: note: Point::Point(double, double)
    point.cpp:7:3: note:   candidate expects 2 arguments, 0 provided
    point.cpp:4:7: note: constexpr Point::Point(const Point&)
    point.cpp:4:7: note:   candidate expects 1 argument, 0 provided
    point.cpp:4:7: note: constexpr Point::Point(Point&&)
    point.cpp:4:7: note:   candidate expects 1 argument, 0 provided
    

    It seems we don't have any default constructor anymore. Only the explicit user defined with two arguments and the implicit copy constructor. Thats right. That c++ standard say, that when a explicit user constructor is provided, the compiler don't have to create default constructors.

    With the new 2011 standard we can explicit request a implicit default constructor!
    Replace this line with the following:

    
    Point() : x(0), y(0) {}
    Point() = default;
    
    $ g++-4.7 -Wall -Wextra -std=c++11 point.cpp 
    $ ./a.out 
    1 2
    Point is POD true
    Point is TrivialType true
    

    Congratulations! We have a object oriented class that is as fast as old C style stuff.

    One important note: Variables in C are not automatic initialized! So our class Point is also not default initialized! See [6] for details. You have to call a constructor explicit e.g.
    Point p = Point();

    Here is some nice code to make sure your types are POD. If something goes wrong and the
    type is not POD, it gave an compiler error

    
    #if __cplusplus >= 201103L
    static_assert(!std::is_polymorphic::value, "Please do not add virtual functions to class Point!");
    static_assert(std::is_pod::value, "Class Point is not POD!");
    #endif
    

    The #if __cplusplus stuff is to check if the compiler has enabled c++11 standard.
    Did you know that gnu g++ has set __cplusplus simply to 1 and this bug was know over 10 years?! The reason is very simple: If they fix it, they broke solaris 8. See [7]. Stupid non standard compliant solaris 8 code!

    You can download the example code here point.cpp.zip

    [1] http://en.cppreference.com/w/cpp/concept/PODType
    [2] http://en.cppreference.com/w/cpp/types/is_pod
    [3] http://en.cppreference.com/w/cpp/concept/TrivialType
    [4] http://en.cppreference.com/w/cpp/concept/TriviallyCopyable
    [5] http://en.cppreference.com/w/cpp/language/default_constructor
    [6] http://en.cppreference.com/w/cpp/language/default_initialization
    [7] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773

    todo:
    *Ich glaube ja nicht daran, dass das Vorhandensein eines Konstruktors den Code langsamer macht.
    *Eine Sache, die ich unterstreichen würde, ist, dass in C++ "harmlos" aussehender Code sehr ineffizient sein kann
    *Für so eine Behauptung muss man schon vernünftige Benchmarks zeigen
    *C++-03 noch kein Moven ga

    20.12.2014

    Fortran COMMON is deadly

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

    In Fortran 77 gibt es den COMMON Block. Das sind sowas wie globale Variablen die man umbenennen kann. Gleich im nächsten Standard (1990) hat man das wieder rausgenommen, weil es eine unheimliche Scheisse ist. (Die Erkenntnis hat ja nur 13 Jahre gedauert).

    Folgenden Beispiel zeigt warum.

    
          SUBROUTINE PREVENTSTART
            COMMON /ROCKETCONTROL/ ISTARTCOUNTDOWN, ITIMELEFT
    
            ! stop the countdown and reset time
            ISTARTCOUNTDOWN = 0
            ITIMELEFT = 1000
          END SUBROUTINE
    
          PROGRAM ROCKET
    
            COMMON /ROCKETCONTROL/ ITIMELEFT, ISTARTCOUNTDOWN
    
            ! initital values
            ITIMELEFT = 1000
            ISTARTCOUNTDOWN = 0
    
            ! now we start the countdown
            ISTARTCOUNTDOWN = 1
    
            ! some countdown loop here
            ! 999
            ! 998
            ! 997
            ! ...
            
            ! Oh no! Stop the countdown
            CALL PREVENTSTART
    
            IF(ITIMELEFT == 0) THEN
              WRITE(*,*) "ROCKET STARTED, YOU ARE DEAD!"
            ELSE
              WRITE(*,*) "COUNTDOWN STOPPED!"
            ENDIF
          END PROGRAM
    
    $ gfortran -Wall rocket.for -o rocket
    $ ./rocket 
     ROCKET STARTED, YOU ARE DEAD!
    

    Shit ;) Ok die Erkenntnis hat gefruchtet. Man hat den Fortran Standard nicht umsonst schon 4 mal geändert. Damit ihr auch versteht wie es richtig geht, hier ein Beispiel im Fortran 2003 Standard.

    
    module RocketControlClass
      implicit none
      private
    
      type, public :: RocketControl
        integer, private :: timeLeft
        integer, private :: countdownIsRunning
    
        contains
    
        procedure :: startCountdown
        procedure :: preventStart
        procedure :: getTimeLeft
      end type
    
      interface RocketControl
        module procedure createRocketControl
      end interface
    
      contains
    
      function createRocketControl() result(this)
        implicit none
        type(RocketControl) :: this
    
        this%timeLeft = 1000
        this%countdownIsRunning = 0
      end function
    
      subroutine startCountdown(this)
        implicit none
        class(RocketControl), intent(inout) :: this
    
        this%countdownIsRunning = 1
      end subroutine
    
      subroutine preventStart(this)
        implicit none
        class(RocketControl), intent(inout) :: this
    
        this%countdownIsRunning = 0
      end subroutine
    
      pure function getTimeLeft(this) result(timeLeft)
        implicit none
        class(RocketControl), intent(in) :: this
        integer :: timeLeft
    
        timeLeft = this%timeleft
      end function
    end module
    
    program rocket
      use RocketControlClass
      implicit none
    
      type(RocketControl) :: control
    
      ! inititalise values
      control = RocketControl()
    
      ! now we start the countdown
      call control%startCountdown
    
      ! some countdown loop here
      ! 999
      ! 998
      ! 997
      ! ...
    
      ! Oh no! Stop the countdown
      call control%preventStart
    
      if(control%getTimeLeft() == 0) then
        write(*,*) "rocket started, you are dead!"
      else
        write(*,*) "countdown stopped!"
      endif
    end
    
    $ gfortran -std=f2003 -Wall rocket.f03 -o rocket2003
    $ ./rocket2003 
     countdown stopped!
    

    Gott sei Dank. Diesmal hat es funktioniert, wir leben noch.
    Für alle die immernoch nicht kapiert haben warum der 77er Code nicht funktioniert: Ich habe die Variablennamen im COMMON Block vertauscht. Einmal ISTARTCOUNTDOWN, ITIMELEFT und einmal ITIMELEFT, ISTARTCOUNTDOWN. Das ist kein Fehler, das ist im Standard so vorgesehen. Kein Compiler und kein forcheck wird diesen Fehler jemals erkennen können. Scheisse, ich sag es ja.

    Kommen wir nun zum 2003er Code. Der ist erstmal deutlich länger. Aber das ist Absicht um einige Konzepte zu zeigen die man für ein ordentlichen Programm so braucht.

    Kommen wir gleich zum wichtigsten: Statt COMMON nutze ich TYPE. Ein type kann wie COMMON Variablen zusammen fassen. Aber er existiert nur einer einzigen Stelle im Code und die Variablennamen kann man nicht mehr umbenennen. Das alleine würde schon langen um den 77er Fehler zu erkennen.

    Aber die Welt dreht sich weiter und seit 1995 gehts erst so richtig rund.

    Ich habe den RocketControl type in ein RocketControlClass - Module ausgelagert. Da Fortran case-insensitive ist, also nicht zwischen GROSS und kleinschreibung! unterschieden wird, muss man selbst seine Variablennamen anpassen. Module bekommen den Suffix "Module" um deutliche zu machen, dass es ein Module ist. Habe ich ein Module welches Objektorientierten Code enthält, bekommt es stattdessen den Suffix "Class" in Anlehung an das class Keyword in C++. *uff* Fortran ist anstrengend.

    Okay zurück zu unserem Programm. Ich habe den type in ein module ausgelagert, und normal lagert man jedes Module in eine eingene Datei aus. Dann bleibt die Übersicht erhalten und auch das Versionskontrollprogramm freut sich.

    Durch das Modul ist es möglich den type RocketControl überall im Programm zu nutzen, ohne die Definition mit allen Variabeln erneut hinschreiben zu müssen. Damit verhindert man nicht nur etliche copy&paste Fehler. Wenn man den type RocketControl um einige Variablen ergänzt, muss nur eine Stelle im Code geändert werden. Mit COMMON müssten alle Stellen im Programm geändert werden, wo RocketControl genutzt wird. Und jedesmal läuft man Gefahr einen Fehler zu machen. Variablen vergessen oder zu vertauschen. Und wie gesagt, mit COMMON kann der Compiler uns nicht vor Fehler beschützen. Werden types benutzt, kommt man erst garnicht in eine Situaton um die erwähnten Fehler zu machen. Der Compiler erledigt den Rest für uns. Und er kann noch mehr!

    Für alle die es nicht wissen: Mit dem use-keyword können Module benutzt werden. Z.B. "use RocketControlModule"

    Das Benutzen von types in Modulen bietet noch weitere Vorteile. Angenommen wird würden unseren type RocketControl um die Subroutine setCountDown(value) erweitern, um anzugeben wie lange der Countdown läuft bis die Rakete startet. Die Subroutine nimmt genau ein Argument "value" entgegen der vom Type Integer sein soll.

    Wenn wir nun einen Fehler machen, und wir sind Menschen, wir machen etliche Fehler... Wenn wir also der Subroutine setCountDown zwei Variablen übergeben, statt nur einer, was dann? Ohne Module sagt der Compiler garnichts. Im günstigsten Falle gibt es ein Warning.
    Das Programm würde laufen, aber könnte auch Abstürzen.

    Das ist doch schön. Wir haben ein offensichtlich falsches Programm, welches keine Compilier und auch keine Laufzeitfehler zeigt. Das ist eine tickende Zeitbombe! Irgendwann wechseln wir den Compiler, oder wecheln den Rechner, oder schalten eine Compileroptimierung dazu und BUMM Segfault beim Funktionsaufruf. Na Geil. Das kann doch kein normaler Mensch debuggen. Vorallem nicht nach 10 20 Jahren.

    Also? Genau, seine Funktionen in Module packen. Ich darf das mal demonstieren:

    rocket.f03:71.32:
    
      call control%setCountDown(1,2)
                                    1
    Error: More actual than formal arguments in procedure call at (1)
    

    Ja ist es denn Wahr, wir haben schon wieder die Welt gerettet.
    Zur Erklärung warum Module die Welt retten: Sieht der Compieler ein Modul, legt er eine .mod Datei an. In unserem Fall würde sie rocketcontrolclass.mod heissen. Benutzt man den gfortran kann man diese Datei sogar mit einem einfachen Texteditor öffnen und sich ansehen. Man sieht in kodierter Form zu jede Funktion ihre Eigenschaften. Wieviel Parameter sie entgegen nimmt und vom welchen Type sie sind.
    Mit einem Module kann der Compiler also sehr einfach unseren Fehler entdecken. Und genau das ist doch eine der Hauptaufgaben von Compiler. Neben der Umwandlung von Text in Binärcode muss er schauen, ob das alles Sinn macht was wir programmiert haben. Meistens stimmt es nicht...

    Ich möchste dieses Beispiel benutzen um einen weiteren beliebten Fehler zu zeigen.
    Angenommen der Benutzer unseres tollen Programms setzt nun CountDown von 5.5 Sekunden. Er übergibt also eine Gleitkommazahl vom Type Real einer Funktion, die einen Integer erwartet. Ohne Module sagt der Compiler nichts, bestensfalls ein Warning.
    Beim Ausführen wird das Bitmuster der Real Zahl als Integer Zahl interpretiert. Dabei kann alles mögliche herauskommen. Sehr größe Zahlen die die Rakete erst nächstes Jahr starten oder negative Zahlen oder gar Null. "ROCKET STARTED, YOU ARE DEAD!" Schonwieder... Nicht so gut.

    Also Module retten mal wieder die Welt. Hier die passende Fehlermeldung:

    rocket.f03:71.28:
    
      call control%setCountDown(1.0)
                                1
    Error: Type mismatch in argument 'value' at (1); passed REAL(4) to INTEGER(4)
    

    Sehr schön. Der Compiler hat uns wieder gerettet.
    Wir schreiben also dem Entwickler dass sein Programm scheisse ist, und es gefälligst auch Kommazahlen unterstützen soll. Der fleissige Entwickler schickt uns sofort die neue Version zu und...

    Error: Type mismatch in argument 'value' at (1); passed REAL(8) to REAL(4)
    

    Verdammt! Was ist denn nun schon wieder? In Fortran können 64Bit Zahlen nicht ohne weiteres in 32Bit Zahlen umgewandelt werden. Das ist auch richtig so. Man würde wertvolle Informationen bei der Umwandlung verlieren und gerade Zahlengenauigkeit ist in der Wissenschaft sehr wichtig. An dieser Stelle muss ich sagen: "Gut gemacht, Fortran Entwickler!" Genießt es, es kommt nicht noch einmal vor.
    Wie löst man das Problem? Auf die richtige Art und Weise? Wir speichern in RocketControl 64Bit Zahlen und geben dem Benutzer die möglichkeit 64Bit oder 32Bit Zahlen einzugeben. Mit Function overloading geht das sehr elegant und die Umwandlung von 32Bit nach 64Bit geht verlustfrei.

    Module können gut die Welt retten. War es das jetzt? Ha! Noch lange nicht. Was ist mit diesem Stück Code?

    
    control%timeLeft = 1.0
    

    Anders als bei Funktionsaufrufe wo man den Stack kaputt machen kann, ist hier die Umwandlung ohne Error Möglich. Man bekommt höchstens ein Warning

      control%timeLeft = 1.0
                         1
    Warning: Possible change of value in conversion from REAL(4) to INTEGER(4) at (1)

    Ja, was nutzen uns all die Funktionen im Module, wenn der Programmierer sie nicht benutzt und stattdessen direkt auf die Variable zugreift. Es sollte jedem einleuchten, dass die Welt wieder verloren ist.

    Glücklicherweise wurde der Fortran Standard nachgerüstet und man kann type Variablen als private markieren.

    
      type, public :: RocketControl
        integer, private :: timeLeft
      end type
    

    Per Default ist "public" vorgegeben, so dass die Variable gelesen und geschrieben werden kann. Gibt man "private" vor, kann die Variable nur noch von Procedure genutzt werden, die RocketControl enthält. Versucht man von ausserhalb auf die Variable lesend oder schreiben zuzugreifen, erhält man einen Compiler Fehler:

    rocket.f03:71.18:
    
      control%timeLeft = 1
                      1
    Error: Component 'timeleft' at (1) is a PRIVATE component of 'rocketcontrol'
    

    Und die Welt ist wieder sicher. Geschützt vor un/absichtlichen Zugriffen von Programmierer die keine Ahnung haben was sie tun. Mein Superheld der Module-Compiler.

    Wir zwingen den Benutzer also die setCountDown Funktion zu benutzen. Und es ist zu 100% sichergestellt, dass der Compiler mit Modulen die gezeigten Fehler erkennt. Jetzt können wir auch folgende Situation gut lösen:

    
    call control%setCountDown(-1)
    

    Negative Werte machen für einen Countdown natürlich keinen Sinn. Wir können in der Funktion den übergebenen Wert auf Gültigkeit überprüfen, eine Fehlermeldung ausgeben und den neue Wert nicht akzeptieren. Da der Benutzer die Funktion setCountDown() aufrufen MUSS, ist auch sichergestellt dass die Überprüfung stattfinden.

    Und wir können uns entspannt zurück lehnen und sicher gehen, dass auch in den nächsten 10 Jahren niemand unser Programm falsch benutzen kann. Selbst wenn er es will. Compiler+Module+neuen Standard sei Dank.

    Anmerkung:
    Wie bereits erwähnt ist "public" default in Fortran. Bei C++ ist es "private" für Klassen. Fortran lebt also in dem Glauben, dass die Programmierer immer alles richtig machen und niemand un/absichtlich eine Variable falsch benutzt.
    In C++ ist die Welt schwarz, jeder hat nur böses im Sinn, niemand kann man trauen, alles muss kontrolliert werden. Wenn wir mathematische Modulle implementieren, welche ein Teil der Umwelt abbilden, welcher Ansatz wäre da wohl realistischer? ;)

    16.11.2014

    2qm 2014 Teil 1

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

    Es ist soweit, Eisenbahnzeit.
    Eine zwei Quadratmeter Bahn soll es werden. Mit langen Bahnhof für die D-Zug Waggons, Pendelzug Stecke und ein paar Abstellgleise. Die Landschaft mit Dorf und Berg darf natürlich auch nicht zu kurz kommen.

    Den Tisch vom letzten Jahr benutzen wir weiter. Sowie die Grundplatte, die wir aber leider auf 103x200cm kürzen mussten.
    Es ist schwierig aber nicht unmöglich eine anspruchvolle Bahn auf 2qm unter zu bringen. Der erste Versuch mit zwei Kehrschleifen würde funktionieren, aber dann bleibt einfach kein Plaz mehr für Abstellgleise oder gar die Pendelzugstrecke.

    Also musste als Grundform wieder der Kreis herhalten. Hier der vorläufige Gleisplan

    2qm2014_16.11_2

    2qm2014_16.11_0

    2qm2014_16.11_1

    Spass mit Pointer

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

    "man kann sich so derbe den kopf weg schiessen damit"

    
    int global;
    
    char *func() {
      return (char*)&global;
    }
    
    int main() {
    
      char *x = func();
      int *RocketPtr = (int*)x;
      *RocketPtr = 1337;
      cout << global;
    }
    

    Output : 1337

    13.11.2014

    Märklin M 4fach Wendekreis

    Filed under: Allgemein — Tags: , — Thomas @ 12:11

    Nach ein paar mir zugeschickten Anregungen für einen Wende/Durchfahrkreis mit Chaos Funktion, hier nur meine Version.
    Um es einfacher zu machen, herrscht hier Rechsverkehr und der Kreis darf nur im Gegenuhrzeigersinn durchfahren werden. Daneben gibt es noch eine Umgehungsmöglichkeit für den Kreisel, damit sich mehrere Loks nicht in die Quere kommen.
    Es ist also Möglich von jeder Seite aus einzufahren und aus jeder Seite wieder auszufahren.

    kreis

    Anbei die WinTrack Datei kreis.zip

    Stückliste
    16x	Mä5106	Gleis gerade 1/1 Länge 180 mm
    4x	Mä5107	Gleis gerade 1/2 Länge 90 mm	
    4x	Mä5108	Gleis gerade 1/4 Länge 45 mm
    12x	Mä5110	Gleis gerade 1/8 Länge 22.5 mm
    8x	Mä5205	Gleis gebogen Ergänzungs- stück
    4x	Mä5100	Gleis gebogen 1/1 Radius 360 mm Normalkreis	
    16x	Mä5101	Gleis gebogen 1/2 Radius 360 mm Normalkreis	
    4x	Mä5202L	Weiche links Radius 437.4 mm Parallelkreis	
    4x	Mä5202R	Weiche rechts Radius 437.4 mm Parallelkreis	
    4x	Mä5140L	Kurvenweiche links	
    4x	Mä5140R	Kurvenweiche rechts	
    

    25.10.2014

    Note Videospiele

    Filed under: Allgemein — Thomas @ 10:10

    http://www.heise.de/newsticker/meldung/Videospielen-in-3D-intensiviert-den-Zorn-2431744.html

    20.10.2014

    howto allocate array in C++ and pass it back to fortran

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

    test.cpp

    
    #include < stdlib.h >
    
    // fortran can only call C routines
    extern "C" {
      // we need the address of the fortran pointer thus a pointer of a pointer.
      void myC_func(int **arr) {   
        // we cannot use new() here because fortran deallocate() use free() instead of delete[]
        *arr = (int*) malloc(12*sizeof(int));
        for(int i=0; i < 12; i++) {
          (*arr)[i] = i;
        }
      }
    }
    

    test.F90

    
    ! https://gcc.gnu.org/onlinedocs/gcc-4.6.2/gfortran/Working-with-Pointers.html
    
    program main
      use iso_c_binding
      implicit none
      
      interface
        subroutine my_routine(arr) bind(c,name='myC_func')
          import :: c_ptr
          ! If a pointer is a dummy-argument of an interoperable procedure, 
          ! it usually has to be declared using the VALUE attribute. 
          ! void* matches TYPE(C_PTR), VALUE, while TYPE(C_PTR) alone matches void**. 
          type(c_ptr), intent(out) :: arr
        end subroutine
      end interface
      
      type(c_ptr) :: cptr
      integer,pointer :: fptr(:)
      
      ! allocate and fill cptr
      call my_routine(cptr)
      ! convert it to fortran pointer
      call c_f_pointer(cptr, fptr, [12])
      
      if(associated(fptr)) write(*,*) "associated"
      write(*,*) fptr
      deallocate(fptr)
      
    end program main
    
    g++ -Wall -Wextra -c test.cpp 
    gfortran -Wall -Wextra -fcheck=all test.F90 test.o
    
    valgrind ./a.out 
    ==5256== Memcheck, a memory error detector
    ==5256== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==5256== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
    ==5256== Command: ./a.out
    ==5256== 
     associated
               0           1           2           3           4           5           6           7           8           9          10          11
    ==5256== 
    ==5256== HEAP SUMMARY:
    ==5256==     in use at exit: 0 bytes in 0 blocks
    ==5256==   total heap usage: 22 allocs, 22 frees, 11,874 bytes allocated
    ==5256== 
    ==5256== All heap blocks were freed -- no leaks are possible
    ==5256== 
    ==5256== For counts of detected and suppressed errors, rerun with: -v
    ==5256== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
    

    14.10.2014

    eneloop pro 2450mAh Akku Erfahrungsbericht

    Filed under: Allgemein — Thomas @ 23:10

    Es wurde Zeit für ein Satz neuer Akkus für die Farradlampe. Drei von vier Akkus haben nur noch die hälfte an Kapazität und einer ist ganz hinnüber (nachdem er mir mal in die Sandbach gefallen war).

    Also bin ich zum Batterie Kaiser gefahren und hab mir 4 neue geholt. Für 20Eur. Macht 5Eur das Stück. Für den Preis müssen die Akkus mich aber überzeugen. Das meinte auch die Verkäuferin. Die eneloop Akkus sollen eine waagerechte Entladekurve haben. Da da bin ich mal gespannt.

    Ich werde einige Lade- und Entladekurven mit unterschiedlichen Ström aufzeichnen.

    Eine genaue Angabe auf der Panasonic Webseite wie lange und mit welchem Strom die Akkus geladen werden, habe ich nicht gefunden. Die Passenden Ladegeräte brauchen etwa 7h für 2000mAh, wenn ich die Angaben richtig gedeutet habe. Das macht 285mA also werde ich mit 300mA laden. Mit 400mA ging es bestimmt auch.

    Hier ist die dritte Entladekurve. Sie fällt schön flach ab. Man bräuhte mal einen anderen Akku zum vergleichen...

    Dritte Entladekurve mit 0.6A

    Dritte Entladekurve mit 0.6A

    Mit Solarstrom vorgeladen.
    Nette Idee. Mit einem Entladestrom von 0.6A kamen noch 1100mAh aus dem Akku. Also lässt sich der Akku durchaus ohne vorheriges Laden verwenden.

    Entladekurve eines frisch gekauften Akkus

    Entladekurve eines frisch gekauften Akkus


    ...

    07.10.2014

    Faster Code – Part 6 – Sprungvorhersage - anschaulich

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

    Sehr schöne anschauliche Erklärung:

    http://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array

    04.10.2014

    merge/connect nearby poylgons

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

    Zwei Polygone verbinden die sich überlappen ist einfach (union).
    Aber was, wenn sich die Polygone nur berühren oder einen sehr kleinen Abstand von einander haben?

    Im Internet findet man kaum etwas. Hier findet man einen Ansatz über die Konvexe Hülle. Ich hab ihn mir noch nicht genauer angesehen.

    Mein Ansatz basiert darauf, die Polygone so zu verbinden, wie man das als Mensch auch machen würde. Also an den Stellen, wo sie sich zu nahe kommen, werden sie verbunden. Und die restlichen, dann überflüssigen, Teile vom Polygon gelöscht.

    Um zu verdeutlichen was genau gemeint ist und wie die Ergebnisse aussehen, hier ein kleines Video.

    Die jetzige Version funktioniert recht stabil. Es gibt noch zwei Sonderfälle die zu behandeln sind. Von der Komplexität her hat der Algorithmus eine quadratische Laufzeit und kann Theoretisch auf linear-logarithmisch gesenkt werden.
    Aber erstmal werde ich überprüfen, ob der Algorithmus auch auf realen Daten zufriedenstellende Ergebnisse liefert.

    « Newer PostsOlder Posts »

    Powered by WordPress