2015-04-29 23 views
8

Nehmen wir an, ich habe zwei arithmetische Typen, eine ganze Zahl, I, und eine Fließkommazahl, F. Ich nehme auch an, dass std::numeric_limits<I>::max() kleiner ist als std::numeric_limits<F>::max().Ist das Floating-Point-Round-Trip-Verhalten immer definiert, wenn der Gleitkommabereich größer ist?

Nun sagen wir, ich habe einen positiven ganzzahligen Wert i. Da der darstellbare Bereich von F größer ist als I, sollte F(i) immer Verhalten definiert werden.

Allerdings, wenn ich einen Gleitkommawert f haben, so dass f == F(i), ist I(f) gut definiert? Mit anderen Worten, ist I(F(i)) immer definiert Verhalten?


entsprechenden Abschnitt aus dem Standard-14 ++ C:

4,9 Gleitpunktarithmetik integrales Konvertierungen[conv.fpint]

  1. A prvalue eines Gleitkommatyps kann in einen prvalue eines Integer-Typs konvertiert werden. Die Konvertierung wird abgebrochen. das heißt, der Bruchteil wird verworfen. Das Verhalten ist nicht definiert, wenn der abgeschnittene Wert nicht im Zieltyp darstellen kann. [Hinweis: Wenn der Zieltyp bool ist, siehe 4.12. - Endnote]
  2. Ein Prvalue eines Integer-Typs oder eines nicht gekürzten Aufzählungstyps kann in einen Prvalue eines schwebenden Punkttyps konvertiert werden. Das Ergebnis ist möglichst genau. Wenn der Wert, der konvertiert wird, in dem Bereich von Werten liegt, die dargestellt werden können, aber der Wert nicht genau dargestellt werden kann, ist es eine implementierungsdefinierte Wahl von entweder dem nächst niedrigeren oder höheren darstellbaren Wert. [Hinweis: Genauigkeitsverlust tritt auf, wenn der Integralwert nicht genau als Wert des Floating-Typs dargestellt werden kann. - Endnote] Wenn der konvertierte Wert außerhalb von den Bereich der Werte darstellt, die dargestellt werden können, ist das Verhalten nicht definiert. Wenn der Quelltyp bool ist, wird der Wert false in Null konvertiert und der Wert true wird in eins konvertiert.
+0

@vsoftco Sie müssen das umformulieren. 'I <= i 'macht keinen Sinn - Sie vergleichen einen Typ mit einem Wert. – orlp

+2

[Nein] (http://coliru.stacked-crooked.com/a/e58cd5864d532045). –

+2

Stellen Sie sich vor, dass 'I' und' F' die gleiche Größe haben, sagen wir 32 Bit. Dann nimm die größte ganze Zahl. Es wird zwangsläufig verlustbehaftet in einen Wert vom Typ "F" konvertiert. Wenn der darstellbare Wert, der ausgewählt wird, größer als die nächste Ganzzahl ist, führt die Rückumwandlung zu UB. –

Antwort

-1

Nr

Es ist möglich, dass i == std::numeric_limits<I>::max(), aber die i ist nicht exakt darstellbar in F.

Wenn der konvertierte Wert in dem Wertebereich liegt, der dargestellt werden kann, aber der Wert nicht genau dargestellt werden kann, ist dies eine implementierungsdefinierte Auswahl für den nächst niedrigeren oder höheren darstellbaren Wert.

Da der nächsthöheren darstellbare Wert gewählt werden kann, ist es möglich, dass das Ergebnis F(i) nicht mehr in I paßt, so Konvertierung zurück undefiniertes Verhalten wäre.

+0

Downvoter, Pflege zu erklären? – orlp

4

Jedoch ist definiert I(f) gut, wenn ich einen Gleitkommawert f so dass f == F(i) haben? Mit anderen Worten, ist I(F(i)) immer definiert Verhalten?

No.

Angenommen, ein Komplement I 32-Bit-Integer-Typ der signierte zwei ist, ist ein 32-Bit F single precision floating point-Typ und i ist die maximale positive ganze Zahl ist. Dies liegt im Bereich des Gleitkommatyps, kann aber nicht genau als Fließkommazahl dargestellt werden. Einige dieser 32 Bits werden für den Exponenten verwendet.

Die Konvertierung von Ganzzahl in Gleitkommazahl ist stattdessen implementierungsabhängig, erfolgt jedoch in der Regel durch Runden auf den nächsten darstellbaren Wert. Dieser gerundete Wert liegt um eins über dem Bereich des Integer-Typs. Die Konvertierung zurück in Ganzzahl schlägt fehl (besser gesagt, es ist undefiniertes Verhalten).

+0

Kleiner Nitpick. _ "Stattdessen wird die Konvertierung von Ganzzahl zu Gleitkomma auf den nächsten darstellbaren Wert gerundet." _ Dies ist nicht garantiert. Es wird eine angrenzende Repräsentation sein, nicht die nächste. – orlp

+0

Technisch gesehen ist dies kein undefiniertes Verhalten, sondern implementationsdefiniertes Verhalten (da es von der Semantik der verwendeten Fließkommatypen abhängt, welche Implementierungen definiert sind). – Wug

+0

@Wug Es ist die Implementierung definiert, wenn es undefiniert sein wird oder nicht :) – orlp

-1

Nein. Unabhängig vom Standard können Sie nicht erwarten, dass diese Konvertierung im Allgemeinen die ursprüngliche Ganzzahl zurückgibt. Es ergibt keinen mathematischen Sinn. Aber wenn Sie in das, was Sie zitiert haben, lesen, zeigt der Standard eindeutig die Möglichkeit eines Präzisionsverlustes bei der Umwandlung von int in float.

Angenommen, Ihre Typen I und F verwenden die gleiche Anzahl von Bits. Alle Bits von I (außer möglicherweise einer, die das Zeichen speichert) werden verwendet, um den absoluten Wert der Zahl anzugeben. Auf der anderen Seite werden in F einige Bits verwendet, um den Exponenten zu spezifizieren, und einige werden für den Signifikanden verwendet. Der Bereich wird wegen des möglichen Exponenten größer sein. Aber der Signifikand wird weniger Präzision haben, da weniger Bits für seine Spezifikation vorgesehen sind.

So wie ein Test, I

gedruckte
std::numeric_limits<int>::max(); 
std::numeric_limits<float>::max(); 

I wieder dann die erste Zahl umgewandelt zu schweben und zurück. Der maximale float hatte einen Exponenten von 38, und der max int hatte 10 Ziffern, also hat float eindeutig einen größeren Bereich. Aber nach dem Umwandeln der Max Int in Float und zurück ging ich von 2147473647 zu -2147473648. So scheint es, dass die Zahl um eine Einheit erhöht wurde und auf die negative Seite ging.

Ich habe nicht überprüft, wie viele Bits tatsächlich für float auf meinem System verwendet werden, aber es zeigt zumindest den Verlust der Genauigkeit, und es zeigt, dass gcc "aufgerundet".

+0

Ich habe nie nach dem ursprünglichen ganzzahligen Wert gefragt. Ich habe nur gefragt, ob die Konvertierung definiert wurde. – orlp

+0

Entschuldigung dafür, dass Sie Ihre Frage nicht sorgfältig gelesen haben. –