[boost.date_time] Plattform-spezifische Caveats?



  • Hallo zusammen

    Folgender Code:

    #include <boost/assign/list_of.hpp>
    #include <boost/assign/list_of.hpp>
    #include <boost/date_time/posix_time/posix_time_types.hpp>
    #include <iostream>
    #include <vector>
    
    using namespace boost::assign;
    using namespace boost::posix_time;
    using namespace std;
    
    int main() {
        time_duration timeStep(minutes(15));
        vector<time_duration> differences(100, minutes(15));
        for (unsigned int i = 0; i < differences.size(); ++i) {
            time_duration::tick_type numerator(timeStep.total_milliseconds());
            time_duration::tick_type denominator(differences.at(i).total_milliseconds());
            double multiplicator = numerator / denominator;
            double random = rand();
            cout << "num: " << numerator << ", " << "den: " << denominator << endl;
            cout << i << ": " << (random * multiplicator) << " (mult: " << multiplicator << ')' << endl;
        }
        return 0;
    }
    

    Gibt auf meinem Entwicklungs-Rechner folgenden Output:

    num: 900000, den: 900000
    0: 41 (mult: 1)
    num: 900000, den: 900000
    1: 18467 (mult: 1)
    ...
    num: 900000, den: 900000
    99: 16541 (mult: 1)
    

    Auf meiner Embedded-Zielplattform hingegen erhalte ich folgenden, ungekürzten Output:

    num: 900000, den: 900000
    0: 6.2635e+09 (mult: 3.47145)
    num: 900000, den: 900000
    1: 6.43756e-301 (mult: 7.61038e-310)
    num: 900000, den: 4614999431078329248
    2: -5936.41 (mult: -3.53002e-06)
    num: 900000, den: 153640644625800
    3: -6053.29 (mult: -3.53036e-06)
    num: 900000, den: -4697926556549346372
    4: 2.49012e+10 (mult: 12.7193)
    num: 900000, den: -4697925780254122828
    1074507244: 3.18828e-301 (mult: 7.51531e-310)
    

    Traurig dabei ist: Wenn ich den "total_milliseconds()"-Teil durch Konstanten ersetze...

    time_duration::tick_type numerator(900000);
    time_duration::tick_type denominator(900000);
    

    funktioniert der Code wie erwartet:

    num: 900000, den: 900000
    0: 1.80429e+09 (mult: 1)
    num: 900000, den: 900000
    1: 8.46931e+08 (mult: 1)
    ...
    num: 900000, den: 900000
    99: 1.9563e+09 (mult: 1)
    

    Gibt es irgendwelche Caveats, dich ich im Zusammenhang mit dieser Funktion beachten sollte?

    Danke für jeden Hinweis und Gruss
    Kessi



  • Nach zusätzlichen Experimenten zeichnet sich ab, dass "time_duration::tick_type" auf dem Zielsystem eine 8-Byte grosse Zahl ist. Sie von Anfang an als "double" zu verwenden, löst das Problem nicht, von "total_milliseconds" auf "total_seconds" zu wechseln aber schon:

    double numerator(timeStep.total_seconds());
    double denominator(differences.at(i).total_seconds());
    

    Das ist für meinen Use Case ausreichend, lässt mich aber mit einem sehr unangenehmen Gefühl zurück. Übrigens, folgender Code funktioniert ebenfalls:

    long numerator(timeStep.total_milliseconds());
    long denominator(differences.at(i).total_milliseconds());
    

    Dabei ist zu beachten, dass "long" auf dem Zielsystem ein 4-Byte Datentyp ist. Die Verwendung von "total_milliseconds" alleine macht den Absturz also noch nicht perfekt, erst, das Resultat in einem "long long" (= "time_duration::tick_type") zu Speichern, bringt das System zum Versagen... Das aber auch nicht im Allgemeinen Fall - anstatt eines Vektors von "time_duration"s nur eine einzelne zu verwenden, löst das Problem ebenfalls.

    time_duration timeStep(minutes(15));
    time_duration difference(minutes(15));
    

    Ich werde mich vorerst auf "total_seconds()" beschränken, muss aber davon ausgehen, dass mir dieses System noch sehr viel Ärger bescherern wird. Vielleicht ist ein Post in der Boost Mailing-Liste ebenfalls angebracht. Werde das bei Gelegenheit nachholen.

    Danke auf jeden Fall an alle Gegenleser und Gruss
    Kessi



  • Um Boost noch komplett aus der Gleichung zu nehmen:

    #include <cstdlib>
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main() {
        long long step(900000);
        vector<long long> differences(100, 900000);
        for (unsigned int i = 0; i < differences.size(); ++i) {
            double numerator(step);
            double denominator(differences.at(i));
            double multiplicator = numerator / denominator;
            double random = rand();
            cout << i << ": " << (random * multiplicator) << " (mult: " << multiplicator << ", " << "num: " << numerator << ", " << "den: " << denominator << ')' << endl;
        }
        return 0;
    }
    

    Resultat:

    0: inf (mult: inf, num: 900000, den: 3.47145)
    1: 5.99277e+13 (mult: 70758.6, num: 900000, den: 7.5603e-310)
    2: 2.14001e-160 (mult: 1.27253e-169, num: 900000, den: -1.26001e-05)
    35420: 2.22566e+14 (mult: 129803, num: 900000, den: -1.26015e-05)
    

    Vektoren von "long long"s sind auf dieser Plattform scheinbar eine böse Sache, denn:

    vector<long long> differences(1, 900000);
    

    ergibt:

    0: inf (mult: inf, num: 900000, den: 3.47145)
    

    aber:

    long long difference(900000);
    for (unsigned int i = 0; i < 100; ++i) {
        double numerator(step);
        double denominator(difference);
        ...
    

    resultiert in:

    0: 41 (mult: 1, num: 900000, den: 900000)
    1: 18467 (mult: 1, num: 900000, den: 900000)
    ...
    99: 16541 (mult: 1, num: 900000, den: 900000)
    

    Ich schätze, jetzt ist es definitiv ein Fall für den Plattform-Hersteller... 😞

    Danke trotzdem für eure Geduld und Gruss
    Kessi



  • Klarer Kompilerfeler :p 😃


Log in to reply