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


von Michi (Gast)


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)


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)


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)


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)


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)


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)


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)


Lesenswert?

Peter D. schrieb:
>   if( val >= (uint32_t)-1 )

Sowas wie UINT_MAX wär wohl besser.

von Markus F. (mfro)


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)


Lesenswert?

A. K. schrieb:
> Sowas wie UINT_MAX wär wohl besser.

Ich wußte grad den Namen des Macros nicht.

von Michi (Gast)


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


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.