Forum: Compiler & IDEs float zu unsigned int: Verhalten bei negativen Zahlen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Michi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich habe folgendes Stück Code, das mit einem GCC 4.6.3 kompiliert wird. 
GetValue() liefert als Rückgabewert einen float.
1
unsigned long helper;
2
float value;
3
4
value = GetValue();
5
6
helper = (value * 1000);
Muss ich damit rechnen, dass das Vorzeichen abgeschnitten wird und der 
Inhalt von 'helper' immer positiv ist?

von Nop (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Das Ergebnis ist nicht definiert für negative Zahlen, weil die 
Darstellung negativer signed integer nicht festgelegt ist. Es wird schon 
irgendein Bitmuster herauskommen, das als unsigned integer interpretiert 
dann natürlich positiv ist. Höchstwahrscheinlich wird aber z.B. eine 
-2.0 nicht als 2 enden.

von Ingo L. (corrtexx)


Bewertung
0 lesenswert
nicht lesenswert
Michi schrieb:
> Muss ich damit rechnen, dass das Vorzeichen abgeschnitten wird und der
> Inhalt von 'helper' immer positiv ist?
Ich würde vor der Rückgabe prüfen ob der Wert <0 ist:
1
if (Rueckgabe < 0) Rueckgabe = 0;

von Yalu X. (yalu) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
Wie Nop schon geschrieben hat, ist das Ergebnis undefiniert. In der
ISO-Norm kannst du das nachlesen:

1
When a finite value of real floating type is converted to an integer
2
type other than _Bool, the fractional part is discarded (i.e., the value
3
is truncated toward zero). If the value of the integral part cannot be
4
represented by the integer type, the behavior is undefined.

Der GCC scheint in solchen Fällen den nächstliegenden darstellbaren Wert
zu nehmen. Bei der Konvertierung eines negativen double oder float in
ein unsigned int ist dieser immer 0.

von Theor (Gast)


Bewertung
3 lesenswert
nicht lesenswert
Man könnte vielleicht Yalus Gedanken so weiterführen:

Falls ein bestimmtes Verhalten undefiniert ist, dann ist es nützlich, 
das erwünschte Verhalten ausdrücklich als Code hin zu schreiben. Das hat 
zwei positive Effekte.

1. und ganz offensichtlich, wird eben genau das erwünschte Verhalten 
erreicht. Und zwar nichts Anderes und definitiv und mit absoluter 
Sicherheit.
2. Die Varianten des unterschiedlichen Compilerverhaltens in einem, dem 
Standard nach undefinierten Fall, müssen nicht jeweils erinnert und 
festgestellt werden und der Code ist ohne weiteres portabel. Es reicht 
im Code eine Bemerkung wie: "Explicitly describing conversion behaviour 
due to undefined case (converting negative floats to unsigned) from 
standard" oder sinngemäß.

Das wäre so meine Idee dazu. Hoffe, dass ist nützlich.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Theor schrieb:
> Falls ein bestimmtes Verhalten undefiniert ist, dann ist es nützlich,
> das erwünschte Verhalten ausdrücklich als Code hin zu schreiben.

Gute Idee.
Z.B.:
1
uint32_t convert( float val )
2
{
3
  if( val <= 0 )
4
    return 0;
5
  if( val >= (uint32_t)-1 )
6
    return -1;
7
  return val;
8
}

von Markus F. (mfro)


Bewertung
1 lesenswert
nicht lesenswert
Peter D. schrieb:
> Theor schrieb:
>> Falls ein bestimmtes Verhalten undefiniert ist, dann ist es nützlich,
>> das erwünschte Verhalten ausdrücklich als Code hin zu schreiben.
>
> Gute Idee.
> Z.B.:
>
1
> uint32_t convert( float val )
2
> {
3
>   if( val <= 0 )
4
>     return 0;
5
>   if( val >= (uint32_t)-1 )
6
>     return -1;
7
>   return val;
8
> }
9
>

Nö. Genau so eigentlich nicht. Undefiniertes Verhalten lässt sich nicht 
mit undefiniertem Verhalten ( (uint32_t) -1) "wegprogrammieren".

Die ISO Dokumentation empfiehlt so was, z.B.:
1
(unsigned long) fmod(fabs(rint(f)), LONG_MAX + 1.0)

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
>   if( val >= (uint32_t)-1 )

Sowas wie UINT_MAX wär wohl besser.

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Nö. Genau so eigentlich nicht. Undefiniertes Verhalten lässt sich nicht
> mit undefiniertem Verhalten ( (uint32_t) -1) "wegprogrammieren".

Nehme alles zurück und behaupte das Gegenteil. Ich hab' da in der Hitze 
des Gefechts (uint32_t) -1.0 gesehen, sorry.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Sowas wie UINT_MAX wär wohl besser.

Ich wußte grad den Namen des Macros nicht.

von Michi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Danke für die zahlreichen Rückmeldungen. Was wäre denn der korrekte Weg 
um das Vorzeichen zu behalten? 'unsigned long' => 'long', aber war's das 
schon?

von Johann L. (gjlayde) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> A. K. schrieb:
>> Sowas wie UINT_MAX wär wohl besser.
>
> Ich wußte grad den Namen des Macros nicht.

UINT32_MAX aus stdint.h / cstdint.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.