C++Guns – RoboBlog blogging the bot

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/

Powered by WordPress