Warum ist das "f" erforderlich, wenn Floats deklariert werden?

85

Beispiel:

float timeRemaining = 0.58f;

Warum ist das fam Ende dieser Nummer erforderlich?

Thomas
quelle
4
Wahrscheinlich, weil es sonst so behandelt würde double.
Uwe Keim
2
0,58 (ohne das Suffix f) ist ein Literal vom Typ double und man kann einem Float keinen doppelten Wert zuweisen, genauso wie man einem String keinen int-Wert zuweisen kann. Sie können jedoch einem Double einen Float-Wert zuweisen, da Sie hier erweitern (C # konvertiert dies implizit für Sie, da keine Genauigkeit verloren geht).
Dave New
Mögliches Duplikat von Warum sollten wir Literale in C # verwenden?
Adatapost
@AVD Obwohl dies ein Duplikat ist, ergibt der obige Fragentitel nicht Ihren Link in der möglichen Duplikatliste. Dies kann also zumindest in Bezug auf mehr Suchkriterien einen Mehrwert bedeuten.
Adam Houldsworth
1
@AdamHouldsworth - alle Straße geht nach double & int .
Adatapost

Antworten:

96

Ihre Erklärung eines Schwimmers besteht aus zwei Teilen:

  1. Es wird deklariert, dass die Variable timeRemainingvom Typ ist float.
  2. Es weist 0.58dieser Variablen den Wert zu.

Das Problem tritt in Teil 2 auf.

Die rechte Seite wird einzeln ausgewertet. Gemäß der C # -Spezifikation wird eine Zahl mit einem Dezimalpunkt ohne Suffix als a interpretiert double.

Wir haben jetzt einen doubleWert, den wir einer Variablen vom Typ zuweisen möchten float. Dazu muss eine implizite Konvertierung von doublenach erfolgen float. Es gibt keine solche Konvertierung, da Sie möglicherweise (und in diesem Fall) Informationen in der Konvertierung verlieren.

Der Grund dafür ist, dass der vom Compiler verwendete Wert nicht wirklich 0,58 ist, sondern der Gleitkommawert, der 0,58 am nächsten kommt, also 0,57999999999999978655962351581366 ... für doubleund genau 0,579999946057796478271484375 für float.

Genau genommen ist das fnicht erforderlich. Sie können die Verwendung des fSuffix vermeiden, indem Sie den Wert in a umwandeln float:

float timeRemaining = (float)0.58;
Jeffrey Sax
quelle
4
Zwei Fragen, wie sind Sie zu der Nummer '0.579999946057796478271484375' gekommen und wie wird die (float) 0.58Arbeit funktionieren? Sie haben vorhin gesagt, dass es keine Konvertierung gibt, da möglicherweise Informationen verloren gehen. Wie kommt es dann, dass die Besetzung funktioniert?
SexyBeast
8
1. Ich habe den Windows-Rechner verwendet, der bis zu 34 Stellen verwendet. 2. Ich sagte, es gibt keine implizite Konvertierung. Eine Umwandlung ist eine explizite Konvertierung. Sie teilen dem Compiler also explizit mit, dass Sie die Konvertierung wünschen, und das ist zulässig.
Jeffrey Sax
Interessant ... Ich hoffe, Sie überwachen diesen Beitrag noch. Ich habe Suffixe kennengelernt, die zuvor für den Webcast, den ich gerade ansehe, auf 'm' gestoßen sind. Wie haben Sie den Windows-Rechner dazu gebracht, .58 als Gleitkommawert anzuzeigen? Ich habe ein paar Knöpfe ausprobiert, die so aussahen, als würden sie dies erzwingen, aber nein ... bekam immer wieder 0,58. Ich muss einen Mann respektieren, der seine Werkzeuge so gut kennt ...
user1585204
Ich verstehe die ganze F-Sache für Float, aber warum? Wenn Sie die Variable als float deklariert haben, sollte sie beim Kompilieren wissen, dass dieser Wert ein float ist. Und wenn Sie das Doppelte erklären. Es macht keinen Sinn, weil Sie float myvalue = 2.4 haben; Beim Kompilieren sollte der Compiler bereits wissen, dass float der Variablentyp ist. Vermisse ich etwas Vielen Dank!
Frank G.
@FrankG. Zwei Gründe: 1. Der Ausdruck 2.4wird überall anders als Doppel interpretiert. 2. Implizite Verengungskonvertierungen (wie von Double zu Float) sind nicht zulässig. Wenn Sie eine Ausnahme von diesen Regeln machen möchten, müssen Sie einen sehr guten Grund haben. Das Speichern von 1 Tastendruck ist wahrscheinlich nicht gut genug.
Jeffrey Sax
36

Da es mehrere numerische Typen gibt, mit denen der Compiler den Wert darstellen kann 0.58: float, doubleund decimal. Sofern Sie nicht damit einverstanden sind, dass der Compiler einen für Sie auswählt, müssen Sie eindeutig unterscheiden.

In der Dokumentation für doubleheißt es, dass der Compiler immer doubleden Typ eines reellen numerischen Literals auswählt, wenn Sie den Typ nicht selbst angeben :

Standardmäßig wird ein reelles numerisches Literal auf der rechten Seite des Zuweisungsoperators als doppelt behandelt. Wenn Sie jedoch möchten, dass eine Ganzzahl als doppelt behandelt wird, verwenden Sie das Suffix d oder D.

Durch Anhängen des Suffixes fwird ein float; das Suffix derzeugt ein double; Das Suffix merstellt ein decimal. All dies funktioniert auch in Großbuchstaben.

Dies reicht jedoch immer noch nicht aus, um zu erklären, warum dies nicht kompiliert wird:

float timeRemaining = 0.58;

Die fehlende Hälfte der Antwort besteht darin, dass bei der Konvertierung von double 0.58zu float timeRemainingmöglicherweise Informationen verloren gehen, sodass der Compiler sich weigert, diese implizit anzuwenden. Wenn Sie eine explizite Umwandlung hinzufügen, wird die Konvertierung durchgeführt. Wenn Sie das fSuffix hinzufügen, ist keine Konvertierung erforderlich. In beiden Fällen würde der Code dann kompiliert.

Jon
quelle
aber wie kann es eine doppelte oder eine dezimale sein, wenn die Variable ein float ist, ich vermisse etwas
Thomas
@BlazArt Ja, der Satz, der besagt, dass der Compiler nicht einmal versucht, das Zuweisungsziel zu überprüfen. Der Grund dafür liegt in den Entwurfsentscheidungen des Compilerteams. Ich würde vermuten, dass es am besten ist, angesichts möglicher Verwirrung explizit zu sein, oder es war zu teuer, sich um die Implementierung zu kümmern, anstatt nur zwei Regeln zu haben, eine für intund eine für double.
Adam Houldsworth
@BlazArt: Ich habe gerade die Antwort ausgearbeitet, bitte schauen Sie noch einmal.
Jon
1
Können Sie mir in Bezug auf den Informationsverlust sagen, wie die Besetzung tatsächlich in Bezug auf das IEEE 754-Format erfolgt, in dem sie gespeichert sind? Double hat eine höhere Präzision. Bedeutet das also, dass das Casting von Float zu Double immer funktioniert double a = 0.69f;?
SexyBeast
@Cupidvogel: Ja, die Spezifikation garantiert (in §6.1.2), dass "die anderen impliziten numerischen Konvertierungen niemals Informationen verlieren", was unter anderem die Konvertierung floatin einschließt double.
Jon
2

Das Problem ist , dass .NET, um einige Arten von impliziten Operationen zu ermöglichen , durchgeführt werden , die mit floatund doublemußten entweder explizit angeben , was in allen Szenarien mit gemischten Operanden oder auch erlaubt implizite Konvertierungen zwischen den Typen in einer durchgeführt werden , geschehen soll , nur Richtung; Microsoft entschied sich dafür, dem Beispiel von Java zu folgen, indem es die Richtung zuließ, die gelegentlich die Präzision fördert, aber häufig die Korrektheit opfert und im Allgemeinen Ärger verursacht.

In fast allen Fällen, die unter doubleWert, der am nächsten an eine bestimmte numerische Größe ist und es eine Zuordnung floatwird die Ausbeute floatWert, der am nächsten zu der gleichen Größe ist. Es gibt einige Eckfälle, z. B. den Wert 9.007.199.791.611.905; Die beste floatDarstellung wäre 9.007.200.328.482.816 (was 536.870.911 entspricht), aber die beste doubleDarstellung (dh 9.007.199.791.611.904) floatergibt 9.007.199.254.740.992 (was 536.870.913 entspricht). Im Allgemeinen ergibt die Konvertierung der besten doubleDarstellung einer bestimmten Menge in floatentweder die bestmögliche floatDarstellung oder eine von zwei Darstellungen, die im Wesentlichen gleich gut sind.

Beachten Sie, dass dieses wünschenswerte Verhalten auch im Extremfall gilt. Beispielsweise floatstimmt die beste Darstellung für die Menge 10 ^ 308 mit der floatDarstellung überein, die durch Konvertieren der besten doubleDarstellung dieser Menge erreicht wird. Ebenso floatstimmt die beste Darstellung von 10 ^ 309 mit der floatDarstellung überein, die durch Konvertieren der besten doubleDarstellung dieser Größe erreicht wird.

Leider sind Konvertierungen in die Richtung, für die keine explizite Besetzung erforderlich ist, selten annähernd so genau. Das Konvertieren der besten floatDarstellung eines Wertes in ergibt doubleselten etwas, das der besten doubleDarstellung dieses Wertes besonders nahe kommt , und in einigen Fällen kann das Ergebnis um Hunderte von Größenordnungen abweichen (z. B. das Konvertieren der besten floatDarstellung von 10 ^ 40 in doubleergibt einen Wert Ein Wert, der größer ist als die beste doubleDarstellung von 10 ^ 300.

Leider sind die Konvertierungsregeln so, wie sie sind. Daher muss man beim Konvertieren von Werten in die "sichere" Richtung mit albernen Typecasts und Suffixen leben und auf implizite Typecasts in der gefährlichen Richtung achten, die häufig zu falschen Ergebnissen führen.

Superkatze
quelle