Wie float in integer wandlen mit Runden?

Gast #7262180
Lesenswert?

Ich habe ein digitales Filter auf einem STM32F411 programmiert, das 
intern mit Gleitkommazahlen rechnet. Nun muss ich diese zwecks Ausgabe 
auf einem AD-Wandler wieder in 16bit-Integers wandeln. Dabei soll zur 
nächstliegenden Ganzzahl gerundet werden. Der einfache cast (int16_t) 
schneidet die Nachkommastellen hingegen einfach ab.

Wie macht man das am elegantesten ohne unschöne Fallunterscheidung?
Gast #7262492
Lesenswert?

Bert schrieb:
> Kann man nicht das Vorzeichen Bit zum multiplizieren verwenden, um die
> Fallunterscheidung zum machen?

Warum so kompliziert (statt straight)?
1
int runden(float f)
2
{
3
int i;
4

5
    if(f >= 0) i = (int) (f+0,5f);
6
    else       i = (int) (f-0,5f);
7
    return i;
8
}
9

10
// oder in einer Zeile
11

12
int runden(float f)
13
{
14
    return (int) (f+f>0?0,5f:-0,5f);
15
}
#7262556
Lesenswert?

A. S. schrieb:
> return (int) (f+f>0?0,5f:-0,5f);

ein schönes Beispiel das man für Anfänger nicht schnell Beispielcode aus 
der Hand reinwirft:

1. float nutzt Dezimalpunkt "." nicht Komma ","


2. der ?: Operator hat niedrigere Priorität als der + Operator.

Ergebnis:

 x = runden(3.5);

 ergibt 0.

 So wäre es richtig
1
int runden(float f)
2
{
3
    return (int) (f+(f>0?0.5f:-0.5f));
4
}
#7264656
Lesenswert?

Bauform B. schrieb:
> round() liefert blöderweise wieder ein double.
> lround() liefert auch kein int, aber immerhin long

hier beim Cortex-M4 muss es natürlich lroundf() heißen
1
  long int lround(double x);
2
  long int lroundf(float x);
3
  long int lroundl(long double x);

Eigentlich wollte ich nur die eure Versuche ins Lächerliche ziehen, 
round() neu zu erfinden. Das geht nun natürlich nicht mehr :( Aber im 
Ernst: wenn man schon sowas selbst baut, obwohl es seit C99 gratis dabei 
ist, sollte man doch mal schauen, ob der M4 nicht einen Maschinenbefehl 
dafür hat. Dann hätte man eine "static inline int runden (float)", die 
aus einem einzigen Maschinenbefehl besteht.

VCVTR sieht gut aus, ich bin nur nicht sicher, ob "round to nearest" 
wirklich der Default ist. Der aktuelle Mode steht im FPSCR[23:22] und 
0b00 wäre der richtige Wert. Aber es gibt noch das "Floating-point 
Default Status Control Register" FPDSCR und die Initialisierungen durch 
Compiler/Runtime/Framework/IDE/Whatever... :(
#7281133
Lesenswert?

rbx schrieb:
> Nur mal so gefragt: hat das Ding keinen "rounding mode", den man in der
> FPU einstellen kann?

Bauform B. schrieb:
> VCVTR sieht gut aus, ich bin nur nicht sicher, ob "round to nearest"
> wirklich der Default ist. Der aktuelle Mode steht im FPSCR[23:22] und
> 0b00 wäre der richtige Wert. Aber es gibt noch das "Floating-point
> Default Status Control Register" FPDSCR und die Initialisierungen durch
> Compiler/Runtime/Framework/IDE/Whatever... :(
#7282829
Lesenswert?

rbx schrieb:
> Nur mal so gefragt: hat das Ding keinen "rounding mode", den man in der
> FPU einstellen kann?

Das finde ich nicht empfehlenswert, denn das würde das Verhalten von 
float-Konvertierungen inkompatibel zu Standard-C machen. Es wird aber 
evtl. Bibliotheksfunktionen oder gar vom Compiler generierten Code 
geben, der dann fehlerhafte Ergebnisse produziert, weil er vom 
Standard-Verhalten ausgeht.

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