C++Guns – RoboBlog blogging the bot

05.06.2017

C++ Guns - Bartek's coding blog - Float vs Double - Überprüft

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

Wieder so ein C++ Blog, der aber in Wahrheit scheiß C Code verbreitet. Und dann erzählt er auch noch die Hälfte und macht unvollständige Angaben zu seinen Tests.

Es geht in dem Artikel darum, dass viele denken, dass floats kleiner und schneller als doubles sein. Kleiner sind sie, ja. Verbrauchen nur 4 Byte statt 8 Byte. Aber schneller sind sie nicht unbedingt. Sollten doch unsere heutigen CPUs mit genügen Hardware ausgestattet sein, um auch 64 Bit Zahlen genauso schnell zu verarbeiten. Na, wir werden sehen...

Endergebnis für ungeduldige:
Für kleine Datenmengen und IEEE Gleitkommazahlen verhalten sich bei meinen Tests floats und doubles gleich.
Verzichtet man auf Standard Zahlen und aktiviert fancy Optimierungen, wird man mit einem 1.5 bis 3.5-fachen schnelleren Programm belohnt, welches falsche Ergebnisse liefern kann.
Für große Mengen sieht die Sache anders aus. Dann wird der RAM Bus zum Flaschenhals.

Im ersten Teil übernehme ich sein Code und versuche die selben Ergebnisse zu erzielen. Im zweiten Teil schreibe ich das ganze nach C++ um. Leider gibt er nicht an, wie groß das Array sein soll und wie viele Iterationen gerechnet werden sollen. Also hab ich mal irgendwas eingestellt um ein paar Sekunden Laufzeit zu bekommen. Wenn man wie im original Artikel nur unter einer Sekunde misst, ist die Varianz zu hoch, und man weiß gar nichts.

Testfall:
AMD Athlon(tm) 64 X2 Dual Core Processor 4800+
32Bit Debian
g++ 6.3.0
ARR_SIZE = 200000
NUM_ITER = 20000

Die Standardeinstellung für 64 Bit Systeme mit Optimierung ist SSE. Ich werde daher explizit auf den floating-point Coprozessor mit der Option -mfpmath=387 umschalten. Für SSE werde ich die Option -mfpmath=sse -msse2 benutzen.

Die Option -ffast-math kann übrigens falsche Ergebnisse liefern. Die exakten Vorgaben der IEEE Spezifikationen werden nicht eingehalten. Dafür sollte man ein schnelleres Programm haben.

Mittelwert von drei Berechnungen pro Einstellung. Alle Angaben in Sekunden.

-O3 -mfpmath=387 -O3 -mfpmath=sse -msse2 -O3 -mfpmath=387 -ffast-math -O3 -mfpmath=sse -msse2 -ffast-math
float 6.54 6.56 6.52 2.01
double 6.61 6.78 6.54 4.54

Also, dasss floats schneller sind als doubles, oder dass doubles schneller sind als floats kann ich in diesem Testfall nicht bestätigen. Bei mir sind sie im Grunde gleich schnell. Nur die Option -ffast-math bewirkt eine Geschwindigkeitsverbesserung um das 3-fache bzw. 1.5-fache.

Aber das kann von CPU zu CPU anders sein. Vor allen von microshit zu GNU.

Testfall 2:
Intel(R) Atom(TM) CPU N270 @ 1.60GHz
32 Bit Debian
g++ 4.9.2
ARR_SIZE = 200000
NUM_ITER = 20000

Mittelwert von drei Berechnungen pro Einstellung. Alle Angaben in Sekunden.

-O3 -mfpmath=387 -O3 -mfpmath=sse -msse2 -O3 -mfpmath=387 -ffast-math -O3 -mfpmath=sse -msse2 -ffast-math
float 21.1 18.9 21.1 6.19
double 22.2 22.2 22.2 31.6

Durch den Sparstrumpf Prozessor zeigt sich insgesamt eine höhere Laufzeit. Floats und doubles sind wieder in etwa gleich schnell. Nur die -ffast-math Option macht einen Unterschied. Für floats eine Verbesserung der Laufzeit wieder um das 3-fache. Und für doubles sehe ich sogar eine Verschlechterung um das 1.5-fache. Das müsste man jetzt versuchen zu erklären...

Testfall3:
AMD FX(tm)-9590 Eight-Core Processor
64 bit Debian
g++ 4.9.2
ARR_SIZE = 200000
NUM_ITER = 20000

Mittelwert von drei Berechnungen pro Einstellung. Alle Angaben in Sekunden.

-O3 -mfpmath=387 -O3 -mfpmath=sse -msse2 -O3 -mfpmath=387 -ffast-math -O3 -mfpmath=sse -msse2 -ffast-math
float 4.45 4.47 1.12 1.17
double 4.45 4.45 2.35 2.34

Die Laufzeit fällt insgesamt, verursacht durch mehr GHz Power. Bis auf -ffast-math sind floats und doubles wieder gleich schnell. Der Geschwindigkeitsvorteil für fast-math liegt wieder bei über 3.5-fach für floats und über 1.5-fach für doubles.

Endergebnis:
Für kleine Datenmengen und IEEE Gleitkommazahlen verhalten sich floats und doubles gleich.
Verzichtet man auf Standard Zahlen und aktiviert fancy Optimierungen, wird man mit einem 1.5 bis 3.5-fachen schnelleren Programm belohnt, welches falsche Ergebnisse liefern kann.
Für große Mengen sieht die Sache anders aus. Dann wird der RAM Bus zum Flaschenhals.

Warum verhält sich die Geschwindigkeit mit -ffast-math so unterschiedlich? Das muss man genauer untersuchen.

http://www.bfilipek.com/2012/05/float-vs-double.html

31.05.2017

C++ Guns - NaN and min() max()

Filed under: Allgemein — Tags: — Thomas @ 21:05

As I told you in my last post, Fortran sucks! This is the C++ Version and its only half as long.


#include <iostream>
#include <limits>
#include <cmath>
using namespace std;

template<typename Func> 
void test(Func func, string funcname, double a, double b, double x) {
  double res = func(a,b);
  cout << funcname << "(" << a << "," << b << ") = " << res << "\n";
  
  if(isnan(x)) {
    if(not isnan(res)) {
      cout << "But should be " << x << "\n";
    }
  } else if(res != x) {
    cout << "But should be " << x << "\n";
  }
}

int main() {
  double NaN = numeric_limits<double>::quiet_NaN();
  test(min<double>, "min", -3.0, NaN, -3.0);
  test(min<double>, "min", NAN, -3.0, -3.0);
  test(min<double>, "min", NAN,  NAN, NAN);
  
  test(max<double>, "max", -3.0, NAN, -3.0);
  test(max<double>, "max", NAN, -3.0, -3.0);
  test(max<double>, "max", NAN,  NAN, NAN);
}

The ugly procedure pointer is replaced with a simple template. But std::min() and std::max() are also template functions. So we must give the compiler a hint which one we want. We want std::min() for doubles. The code is fine, nothing more to say. Except it dosent work as expected ;)

FORTRAN - NaN and min() max()

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

What happens if one put NaN into min() or max()? Will it return NaN or the other number? Is it deterministic or random?
Sounds easy to test but its hard to implement. For example: How one get a quite-NaN number? A quite-NaN dosen't trigger debug traps, signaling-NaN do. There is no standard way in pre Fortran 2003! One have to google some nasty integer-float bit tricks. But with Fortran 2003 there is an intrinsic module ieee_arithmetic, which has the function ieee_value() which can return a quite-NaN. And one can test for Nan wich the function ieee_is_nan().

Remeber, C++ provide this functionality with std::numeric_limits::quite_nan() in C++1998 or earlier.

So the test ist quite simple. We put a number and NaN into min() and compare the result with our expected number. We do this for every combination and for min() and max(). The result for gfortran 6.3.2 32bit is: The returned number is alway not NaN, expect for the case where both parameter are NaN. Then, the function has no choice and returns NaN.

Back to the implementation. We want an automatic test, to quick start the program on different hardware and software settings. With a nice console output what happens, and what happens wrong.
There are two ways to do this. The easy one with lots of code duplication. And the right on, with only on test() function which get called for one test.
The test() function gets a varliable a, b which we wanna test. x als the expected result. A procedure pointer to either min() or max() and a short string with the function name we wanna test. For example:

call test(func, "min", 3.0, NAN, 3.0);

But... one can not get a procedure pointer on a intrinsic function!?? And if you implement your own function, it has to be a subroutine!??

Fortran is broken by design.

This ends up in lot more code and paint than is has to. See my next post where I implement this test in C++. Without pain and only half of code size.

Here is the 56line problem:


module test_m
  use, intrinsic :: IEEE_ARITHMETIC
  contains
  
  subroutine test(func, funcname, a, b, x) 
    implicit none
    procedure(), pointer :: func => null()  
    real, intent(in) :: a, b, x
    character(len=*), intent(in) :: funcname
    real :: res
    
    call func(a,b,res)
    write(*,*) funcname, "(",a, ",", b, ") =", res
    
    if(ieee_is_nan(x)) then
      if(.not. ieee_is_nan(res)) then
        write(*,*) "But sould be", x
      endif
    else if(res /= x) then
      write(*,*) "But should be", x
    endif    
  end subroutine

  subroutine mymin(a,b, x)
    implicit none
    real, intent(in) :: a, b
    real, intent(out) :: x
    x = min(a,b)
  end subroutine
  
  subroutine mymax(a,b, x)
    implicit none
    real, intent(in) :: a, b
    real, intent(out) :: x
    x = max(a,b)
  end subroutine
end module

program fmin    
  use test_m
  implicit none
  real :: NAN
  procedure(), pointer :: func => null()
  
  NAN = IEEE_VALUE(NAN, IEEE_QUIET_NAN)

  func => mymin  
  call test(func, "min", -3.0, NAN, -3.0)
  call test(func, "min", NAN, -3.0, -3.0)
  call test(func, "min", NAN, NAN,  NAN)

  func => mymax  
  call test(func, "max", -3.0, NAN, -3.0)
  call test(func, "max", NAN, -3.0, -3.0)
  call test(func, "max", NAN, NAN,  NAN)
end program

11.05.2017

C++ Guns - Why isn't there a swap function in Fortran and C?

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

Because Fortran and C sucks.
To implement a generic swap function which works for any type and any custom type, one needs templates. Think about usually variables which store a value. Templates are variables which store types. But Fortran and C do not have template techniques. So one must implement a swap function for every type and any future custom type by himself. And pay the cost of a not-inline function call.

With C++ you don't even have to think about it.


template<class T>
inline void std::swap(T& a, T& b) noexcept;

09.05.2017

Garten - Es sprießt

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

Nach genau 26 Tagen nach der Aussaat sprießen die ersten Grashalme hinten im Garten. Das kam mir doppelt so lange vor. Jetzt dauert es nicht mehr lange, bis ein grüner Teppich entsteht :D

06.05.2017

Garten - Tomaten

Filed under: Allgemein — Tags: — Thomas @ 21:05

Meine Geburtstagstomatenpflanze hat nun ihren Weg in den Garten befunden. Ich hoffe, der ausgewählte Platz ist auch genügen sonnig, und der Boden gut. Und die Nachbarpflanzen freundlich. Und falls es regnet, soll die Pflanze überdacht stehen. Zumindest steht das auf dem Beipackzettelchen so geschrieben.

tomatenpflanze

Neues Bücherregal

Filed under: Allgemein — Thomas @ 20:05

Ich wollte schon lange ein neues Bücherregal haben. Und als ich letztens zwei große Bretter auf dem Sperrmüll sah, hab ich sie mitgenommen und zersägt.
Im Keller lagen auch noch die Regalhalterungen aus der letzten Wohnung. Das Anbringen war aber garnicht so einfach. Die Wand besteht irgendwie nur aus Putz?! Aber ganze 18 Schrauben später und das Ding war fest.
Um keine extra Buchstützen zu benötigen, habe ich an die vier Regalbretter einfach seitlich noch zwei geschraubt. Jetzt muss nur noch der Umleimer komplett aufgeklebt werden und fertig.

regal

05.05.2017

Aldi Thermomix Reparatur - Rückwärtsgang

Filed under: Allgemein — Thomas @ 22:05

Update 06.2021
Mir wurde gesagt, das Ding ist nun kaputt. Irgendwas dreht durch. Scheint kein elektrischer Fehler zu sein. 5 Jahre hat es mit Reperatur gehalten. Mehr war nicht zu erwarten.

Vor ein paar Tagen ging unsere Küchenmaschine, der Aldi Thermomix Quigg 2014, einfach nicht mehr an. Mir nichts, dir nichts, von jetzt auf gleich, kaputt. Da war der Frust natürlich hoch. Das Ding ist kaum ein Jahr alt, kaum benutzt, hat stolze 200EUR gekostet und schon kaputt?! Die Garantie ist natürlich auch abgelaufen, und/oder die Rechnung weg.
Aber das ist alles kein Problem. Ich wollte das Teil eh schon am ersten Tag aufschrauben und nachschauen, ob man da einen Rückwärtsgang einbauen kann. Denn was macht ein Mixer der andersherum läuft? Na klar! Rühren! Das ist das ultimative Feature, welches dem Thermomix Klon noch fehlt. Kneten kann er ja auch. Sofern man den Knet-Einsatz nicht schon kaputt gemacht hat.
Also, lasst uns das Gerät aufschrauben! Gesagt, getan. Es geht nicht auf. Die haben wohl dieses Ding, was den Mixerbehälter antreibt, wohl direkt auf die Motorwelle geschrumpft. Entweder ich mache alles kaputt, oder das Gehäuse bekommt ein paar Löcher.
Nachdem die Elektronik nun frei lag, war der Fehler auch schnell gefunden. Eine simple, einfache, doofe, Gleichrichterdiode war hinüber. Das ist sehr peinlich für den Hersteller. Ich meinte die Diode für die mC Elektronik, direkt hinter dem Schaltnetzteil. Gleich darauf kommt der 7805, der 1A verträgt. Die Diode verträgt auch 1A. Aber die Stromaufnahme ist, ich hab es nachgemessen, nur 0.05 bis 0.1A. Der Strom hat also die Diode nicht gekillt. Wie sieht es mit der Hitze aus? Nein, in dem Gerät wird nichts wirklich heißt. Es war auch die ganze Zeit über Aus. Da fliesst nur ein Standy-By Strom.
Bleibt noch die Spannung. Es war eine 100V Diode an ca. 10V Spannung. Sie hätte also 10mal mehr Spannung abbekommen müssen um zu sterben. Das hätte aber auch 10mal mehr Spannung auf der anderen Seite des Transformators bedeutet. Aber alle anderen Geräte im Stromnetze funktionieren auch noch. Was bleibt noch übrig? Wahrscheinlich Millionen kleiner fieser Spannungsspitzen von dem Kohlenmotor.
Oder womöglich hatten wir einfach nur Pech.

Kommen wir zum zweiten Teil: den heiß ersehnten Rückwärtsgang.
Eins vorweg: Um die Drehrichtungsumkehr einzubauen, muss der komplette Thermomix zerlegt werden! Wer es sich also nicht zutraut, der soll es dennoch versuchen :D Denn es war ja schon kaputt...
Der Motor ist ein simpler Reihenschlussmotor mit zwei Drehzahlen. Um die Drehrichtung umzukehren, langt es nicht einfach die Anschlüsse zu tauschen. Da, wie der Name schon sagt, die Spule von Stator und Läufer in Reihe geschaltet sind. Vielmehr muss nur der Anschluss der Spule vom Läufer gedreht werden. Dies erledigt ein simpler 2-pol Umschalter für 1.5Eur. Die Anschlüsse habe ich dabei direkt am Motor abgenommen, und nicht an der Platine. Daher auch der komplette Ausbau des Motors. Das ist aber wirklich nicht mehr. Man muss nur alles abmontieren und in umgekehrter Reihenfolge wieder anschrauben.
Aber Vorsicht: Wenn der Motor sich anders herum dreht, ändert sich auch die Luftströmung für die Kühlung. Da der Thermomix aber einen eingebauten Ventilator hat, dessen Luftrichtung sich nicht ändert, so hebt sich die Wirkung auf. Und der Motor läuft im Rückwärtsbetrieb ungekühlt! Ob, und wie lange, das bei kleiner Leistung gut geht, bleibt abzuwarten ;)

thermomix1

Thermomix mit Rückwärtsgang Schalter

Thermomix mit Rückwärtsgang Schalter

01.05.2017

The Leapfrog Integrator

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

Also Leapfrog ist voll cool. Es berechnet nicht Ort und Geschwindigkeit zum selben Simulationszeitpunkt, sondern versetzt. Frei nach dem Quantenprinzip, dass nicht Ort und Geschwindigkeit gleichzeitig mit beliebiger Genauigkeit gemessen werden kann.

Das Beispiel ist im ekligen C Code überhaupt geschrieben. Zeit es umzuschreiben.
Interessanterweise ist die C++ Version mit t_max=1000000 mit 6.8sec statt 8.4sec sogar um 20% schneller. Ich denke es liegt an den Schleifen die besser optimiert werden können, da die Anzahl der Iterationen fix zur Compilezeit ist. Und diese Information durch die constexpr size() Funktion des std::array Containers auch dem Compiler bekannt ist. Im Gegenzug zur C Version. Wo die Anzahl zwar auch fix zur Compilezeit ist, aber durch eine Laufzeit Variable n im Programm umher gereicht wird. Sonst ist der Code ja gleich.

Anbei die erste C++ Version und der C Code als Vergleich. Mehr wird folgen

inverse_square.c

inverse_square_part1.cpp

[1] https://de.wikipedia.org/wiki/Leapfrog-Verfahren
[2] https://www.physics.drexel.edu/students/courses/Comp_Phys/Integrators/leapfrog/

30.04.2017

Modellbahn Veränderungen

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

Seit über zwei Jahren steht die Anlage nun im Wohnzimmer... und staubt ein. Auf der Oberfläche ist sie eigentlich fertig. Die Gleise sind schon lange verlegt. Die Häuser gestellt, die Strassen gemalt und der Rasen gestreuselt.
Was fehlt ist die Elektronik.
Vor ein paar Monaten hatten wir einen Rückschlag mit der automatischen Wendezugsteuerung. Irgendein Transistor ist wohl durchgebrannt - trotz Sicherung. Wir hatten beschlossen die IC Steuerung durch Relais zu ersetzen. Aber es zieht sich alles länger als gewünscht.

Man darf dabei nicht das große Ziel aus den Augen verlieren. Die Weihnachtsausstellung in der dritten Dezemberwoche im Rathaus, wo wir unsere Anlage präsentieren wollen. Natürlich voll automatisiert. Allerdings nimmt die Anlage im kleinen Raum viel Platz ein, und steht fast 7 Tage herum, bis ich Sonntags mal ein oder zwei Stunden komme und Teste oder Kabel verlege. Um der Sache neuen Anreiz zu geben, und um den Termin einzuhalten, haben wir beschlossen dass die Anlage umzieht, zu mir in den Keller.
Das bietet eine Reihe von Vorteilen:
Ich kann auch unter der Woche einfach mal Abend noch für eine halbe Stunde runter in den Keller gehen und etwas testen.
Oder in Ruhe die Relais Platinen etwas weiter löten.
Sonntags ist mehr Zeit für Sommer-Dinge.
Der ein oder andere hat Interesse bekundet, und man kann sich spontan auch unter der Woche treffen und weiter bauen.

Nachteile gibt es allerdings auch:
Ich muss den Keller aufräumen -_- Okay, das ist streng genommen kein Nachteil, sondern dringend nötig.
Der Transport. Das Ding ist 2x1x0.3m und muss irgendwie bewegt werden. Und mein Kellerabteil ist nicht groß. Es wird wohl nur ein Gang von 60cm breite bleiben.

Aber in der Summe bin ich zufrieden mit der Entscheidung. Es muss vorwärts gehen und es gilt noch einige Relais zu verlöten.

« Newer PostsOlder Posts »

Powered by WordPress