ESP32 und C++, Nachkommastellen verschwinden

#6689789
Lesenswert?

Hallo,
ich versuche gerade für den ESP32 aus der Arduino-IDE heraus eine 
Berechnung zu realisieren. Eigentlich ganz simpel, allerdings werden 
unerwünschterweise die Nachkommastellen gerundet ... kann mir jemand 
einen Tipp geben?

Die Eingangswerte stammen im Byte-Format von der RTC, irgendwo muss ich 
also casten. Unterhalb von "D= ..." sollte die berechnung in einer Zeile 
erfolgen, ich hab das jetzt nur zur Fehlereingrenzung auf Einzelschritte 
gesplittet:
1
float julianDate(byte gYear, byte gMonth, byte gDay, byte gHour, byte gMinute, byte gSecond)
2
{
3
    int Y, M, B;
4
    float D, ret;
5
    float T1, T2, T3, T4, T5;
6

7
    if (gMonth > 2)
8
    {
9
        Y = gYear + 2000;
10
        M = gMonth;
11
    }
12
    else
13
    {
14
        Y = gYear + 2000 - 1;
15
        M = gMonth + 12;
16
    }
17

18
    B = 2 - Y / 100 + Y / 400;        // Ganzzahl!
19

20
    D = gDay + (gHour * 3600 + gMinute * 60 + gSecond) / (float)86400;
21

22
    T1 = floor(365.25*(static_cast<float>(Y)+4716.0));
23
    Serial.printf("T1: %f\r\n", T1);
24
    T2 = floor(30.6001*(static_cast<float>(M)+1.0));
25
    Serial.printf("T2: %f\r\n", T2);
26
    T3 = D;
27
    Serial.printf("T3: %f\r\n", T3);
28
    T4 = static_cast<float>(B);
29
    Serial.printf("T4: %f\r\n", T4);
30
    T5 = 1524.5f;
31
    Serial.printf("T5: %f\r\n", T5);
32

33
    ret = T1;
34
    Serial.printf("ret1: %f\r\n", ret);
35
    ret = ret + T2;
36
    Serial.printf("ret2: %f\r\n", ret);
37
    ret = ret + T3;
38
    Serial.printf("ret3: %f\r\n", ret);
39
    ret = ret + T4;
40
    Serial.printf("ret4: %f\r\n", ret);
41
    ret = ret - T5;
42
    Serial.printf("ret5: %f\r\n", ret);
43

44
    return ret;
45
}

Ein Beispiel der mitgeloggten Zwischenergebnisse:
1
T1:   2460689.000000
2
T2:   183.000000
3
T3:   13.451875
4
T4:   -13.000000
5
T5:   1524.500000
6
ret1: 2460689.000000
7
ret2: 2460872.000000
8
ret3: 2460885.500000
9
ret4: 2460872.500000
10
ret5: 2459348.000000

T3 wird richtig mit reichlich Nachkommastellen berechnet, beim 
Aufsummieren wird plötzlich gerundet, was mache ich da falsch?

Grüße
Thilo
#6689803
Lesenswert?

Auch float hat nur einen begrenzten Dynamikbereich den du hier knackst.
Bei ret3 sieht man das gut. Du erwartest was mit vielen 
Nachkommastellen. Durch die große Zahl ist dies allerdings nicht mehr 
möglich, deshalb sind die Nachkommastellen "gerundet".

Gib Mal hier [1] eine Zahl wie 2460885.451875 ein und drück auf Enter. 
Dann siehst du das Problem.

[1]  https://www.h-schmidt.net/FloatConverter/IEEE754.html
#6689825
Lesenswert?

Thilo G. schrieb:
> T3 wird richtig mit reichlich Nachkommastellen berechnet, beim
> Aufsummieren wird plötzlich gerundet, was mache ich da falsch?

Wie viele signifikante Stellen erwartest du von einer 32-Bit 
Flieskommazahl?

Du hast eine Mantisse von 23 Bit, damit wären Integerzahlen von grob +-4 
Millionen darstellbar.
Die Zahl 2460689 schöpft fast schon das Maximum aus, da bleibt für die 
Nachkommastellen nicht mehr viel übrig, genau gesagt ein Bit und das ist 
genau das was du siehst.

Wenn du genauere Ergebnisse benötigst, dann musst du double anstatt 
float verwenden, nur weiß ich nicht, ob der ESP32 dies überhaupt 
unterstützt.

Alternativ: verwende Festpunkt-Arithmetik.

  Michael
#6689834
Lesenswert?

erklehr behr schrieb:
> Jetzt erkläre mir bitte was Float Zahlen in Datums-Berechnungen
> zu suchen haben.

Das will mal eine Teleskopnachführung werden, da brauche ich für die 
weiteren Berechnungen das Julianische Datum incl. Tagesbruchteilen. Da 
ich die begrenzte Genauigkeit von float nicht auf dem Schirm hatte, muss 
ich jetzt erstmal sehen, wie ich das sinnvoll löse.

Grüße
Thilo
#6689861
Lesenswert?

Michael D. schrieb:
> Wenn du genauere Ergebnisse benötigst, dann musst du double anstatt
> float verwenden, nur weiß ich nicht, ob der ESP32 dies überhaupt
> unterstützt.

Ich hab's mal schnell probiert, es funktioniert mit double. Allerdings 
werde ich mir das Timing mal noch in Ruhe ansehen, der ESP32 bekommt ja 
noch deutlich mehr zu rechnen und soll sekündlich aktualisieren. Aber da 
ich jetzt weiß, wo es geklemmt hat, werde ich die nächsten Tage mal den 
kompletten Rechenumfang grob zusammenbauen, um zu sehen, ob er's schafft 
oder ich anders rangehen muss.

Grüße
Thilo
Gast #6689863
Lesenswert?

Thilo G. schrieb:
> Das will mal eine Teleskopnachführung werden, da brauche ich für die
> weiteren Berechnungen das Julianische Datum

Warum musst du dich unbedingt auf den 1. Januar −4713 v. Chr. beziehen.
Meist wird das Problem umgangen, indem man nicht das Julianische Datum, 
sondern das Modifizierte Julianische Datum verwendet. Um mehr 
Nachkommastellen zur Verfügung zu haben, gibt es auch noch den Typ 
double
#6689866
Lesenswert?

Mit JD*1000 hättest du in einem uint32 bereits 3 Nachkommastellen.
Wenn du mehr brauchst wäre es vllt sinnvoll Ganztage und Tagesbruchteile 
zu trennen und für die Tagesbruchteile eine geeignete Normierung zu 
verwenden.
z.B.
1
struct tJulianDate
2
{
3
uint32_t u32Days;
4
uint16_t u16DayFrac;
5
}

Gekapselt in einer Klasse könntest du auch die Operatoren überladen um 
damit leicht rechnen zu können.
#6689877
Lesenswert?

Thilo G. schrieb:
> werde ich mir das Timing mal noch in Ruhe ansehen, der ESP32 bekommt ja
> noch deutlich mehr zu rechnen und soll sekündlich aktualisieren

Dazu hier noch ein interessanter Artikel, vor allem zu Thema Division 
und den Libraries welche man verwenden sollte:
https://blog.llandsmeer.com/tech/2021/04/08/esp32-s2-fpu.html

Es kann sogar schneller sein, wenn du double anstatt float verwendest.

Ein mal pro Sekunde ist jetzt nicht wirklich eine Herausforderung :-)

 Michael
Gast #6690176
Lesenswert?

Danke nochmal an alle, ich kenne da nun meine Baustellen und werde mir 
die Lösungsvorschläge in Ruhe ansehen.
Ich will mir letzten Endes nur die Ist-Koordinaten anzeigen lassen - 
umschaltbar in drei unterschiedlichen Koordinatensystemen - um damit 
gezielt Objekte anfahren zu können.
Die erforderliche Auflösung fürs Fotografieren soll der Schrittantrieb 
unabhängig davon erreichen. Da muss dann nur die Interruptfrequenz zur 
Untersetzung incl. Mikroschritten passen.

Einen schönen Feiertag an alle!
Thilo

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren