arm gcc none eabi: Wie wird ein float/double gespeichert

Gast #3786219
Hallo Leute. Ich will einen float Wert zu einem anderen µC übertragen. 
Ich hatte vor den float auf meinem stm32 byteweise auf den anderen 
controller zu schieben. Soweit kein Problem. Das problem ist, der 
empfangende Controller ist kein STm32/ kein ARM!!. Somit muss ich wissen 
nach welchem schema der Compiler den Float abspeichert. Weiß jemand was?


Ps: Wie ein Double gespeichert wird würde mich auch interessieren :)
Gast #3786250
>Somit muss ich wissen
>nach welchem schema der Compiler den Float abspeichert.

Nimm deinen Debugger, speichere 1.2345f irgendwo als
volatile float ab und vergleiche den Inhalt im Speicher.
Gast #3786308
>Der Stm32f4 hat eine FPU!

Double kann die übrigends nicht. Das wird in Software gemacht.

Jetzt frage ich mich nur noch weshalb man ein float
von einem Zahlenmonster zum anderen verschicken will.
Gast #3786412
A. K. schrieb:
> M. H. schrieb:
>> Der STM32 ist ein ARM??!?!?!?!?!
>
> Die STM32 haben Cortex-M Cores, und die sind von ARM.

Das weiß ich auch.. Ich glaube wenn man das nicht wüsste siehts schlecht 
aus mitm Programmieren :)

Ich hab nur den Kontext der Aussage verramscht. Mein Satz war eine 
Feststellung, mit verwirrtem Hintergrund
Gast #3786419
M. H. schrieb:
> Somit muss ich wissen
> nach welchem schema der Compiler den Float abspeichert. Weiß jemand was?

Guck's dir einfach an. Leg dir ein float Variable in den Speicher, setzt 
sie auf 1.0 und dann guck dir an, was im Speicher passiert, wenn du sie 
in einer Schleife immer weiter durch 2 teilst bzw. mit 2 multiplizierst. 
Damit siehst du schnell wie der Exponent incl. Vorzeichen liegt. Und 
dann ist der Rest einfach die Mantisse. Wegen der Normalisierung ist das 
erste Bit langweiig und wird meist weg gelassen.
#3786432
Die einzig wirklich robuste und portable Option wäre es wohl die float 
bzw. double Zahl in einen String (oder ein anderes "standardisiertes" 
Format) zu bringen, und anschließend dieses zu übertragen. Das ist zwar 
mit Overhead verbunden (printf, scanf, usw.), dafür aber unabhängig von 
der verwendeten Hardware und verschiedenen Software Implementierungen.

Wie kommunizieren die beiden Mikrocontroller denn eigentlich? UART? SPI? 
I2C?

Mit freundlichen Grüßen,
Karol Babioch
Persönliche Seite #3821083
Eine exakte Serialisierung ohne printf bekommt man fast schon mit 
Standardmitteln hin:
 
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <inttypes.h>
4
#include <math.h>
5

6
// double = sign * mant * 2 ^ (ex - __DBL_MANT_DIG__)
7
typedef struct
8
{
9
    int sign, ex;
10
    uint64_t mant;
11
    char s_mant[2 + __DBL_MANT_DIG__ /* GCC */];
12
} double_t;
13

14
void d2d (double x, double_t *d)
15
{
16
    uint64_t mant = 0;
17
    d->sign = copysign (1.0, x) < 0.0 ? -1 : 1;
18
    double r = frexp (copysign (x, 1.0), & d->ex);
19
    char *s = d->s_mant;
20
    
21
    *s++ = '.';
22
    for (int i = 0; i < __DBL_MANT_DIG__ /* GCC */; i++)
23
    {
24
        r = ldexp (r, 1);
25
        unsigned b = r >= 1.0;
26
        r -= b;
27
        mant = (mant << 1) | b;
28
        *s++ = '0' + b;
29
    }
30
    *s++ = '\0';
31
    d->mant = mant;
32
}
33

34

35
int main()
36
{
37
    int mdig = __DBL_MANT_DIG__; // GCC
38
    double x = -1.000000000000001;
39
    double_t d;
40
    for (int i = 0; i < 10; i++)
41
    {
42
        d2d (x, &d);
43
        printf ("%.16f = %c0b0%s * 2^%d\n", x,
44
                d.sign > 0 ? '+' : '-', d.s_mant, d.ex);
45
        x = nextafter (x, HUGE_VAL);
46
    }
47

48
    return EXIT_SUCCESS;
49
}

Gibt:
 
1
-1.0000000000000011 = -0b0.10000000000000000000000000000000000000000000000000101 * 2^1
2
-1.0000000000000009 = -0b0.10000000000000000000000000000000000000000000000000100 * 2^1
3
-1.0000000000000007 = -0b0.10000000000000000000000000000000000000000000000000011 * 2^1
4
-1.0000000000000004 = -0b0.10000000000000000000000000000000000000000000000000010 * 2^1
5
-1.0000000000000002 = -0b0.10000000000000000000000000000000000000000000000000001 * 2^1
6
-1.0000000000000000 = -0b0.10000000000000000000000000000000000000000000000000000 * 2^1
7
-0.9999999999999999 = -0b0.11111111111111111111111111111111111111111111111111111 * 2^0
8
-0.9999999999999998 = -0b0.11111111111111111111111111111111111111111111111111110 * 2^0
9
-0.9999999999999997 = -0b0.11111111111111111111111111111111111111111111111111101 * 2^0
10
-0.9999999999999996 = -0b0.11111111111111111111111111111111111111111111111111100 * 2^0

Wie man sieht zählt die Mantisse in jedem Schritt brav um 1 LSB hoch. 
Hinzu kommt dann noch Behandlung von NaN, Inf, Denormals, +/-0, etc.

Wem die Schleife zu unbequem ist oder keine String-Darstellung braucht 
kann auch einfach
 
1
d->mant = ldexp (r, __DBL_MANT_DIG__);

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.