Pourquoi le «f» est-il requis lors de la déclaration des flottants?

86

Exemple:

float timeRemaining = 0.58f;

Pourquoi le fest-il obligatoire à la fin de ce numéro?

Thomas
la source
4
Probablement, car sinon, il serait traité comme double.
Uwe Keim
2
0.58 (sans le suffixe f) est un littéral de type double et on ne peut pas assigner une valeur double à un float, tout comme on ne peut pas assigner une valeur int à une chaîne. Cependant, vous pouvez attribuer une valeur flottante à un double car ici vous élargissez (C # convertira implicitement cela pour vous car aucune précision ne sera perdue).
Dave New
doublon possible de Pourquoi utiliser des littéraux en C #?
adatapost le
@AVD Bien qu'il s'agisse d'un doublon, le titre de la question ci-dessus ne donne pas votre lien dans la liste des doublons possibles. Cela peut donc être une valeur ajoutée en termes de critères de recherche au moins.
Adam Houldsworth
1
@AdamHouldsworth - tout le chemin mène double & int .
adatapost le

Réponses:

96

Votre déclaration de flotteur contient deux parties:

  1. Il déclare que la variable timeRemainingest de type float.
  2. Il affecte la valeur 0.58à cette variable.

Le problème se produit dans la partie 2.

Le côté droit est évalué seul. Selon la spécification C #, un nombre contenant un point décimal qui n'a pas de suffixe est interprété comme undouble .

Nous avons donc maintenant une doublevaleur que nous voulons affecter à une variable de type float. Pour ce faire, il doit y avoir une conversion implicite de doubleenfloat . Il n'y a pas de telle conversion, car vous pouvez (et dans ce cas faire) perdre des informations lors de la conversion.

La raison en est que la valeur utilisée par le compilateur n'est pas vraiment 0,58, mais la valeur en virgule flottante la plus proche de 0,58, qui est 0,57999999999999978655962351581366 ... pour doubleet exactement 0,579999946057796478271484375 pour float.

À proprement parler, le fn'est pas obligatoire. Vous pouvez éviter d'avoir à utiliser le fsuffixe en convertissant la valeur en a float:

float timeRemaining = (float)0.58;
Jeffrey Sax
la source
4
Deux questions, comment êtes-vous arrivé au nombre «0.579999946057796478271484375», et comment cela (float) 0.58fonctionnera-t-il? Vous avez dit plus tôt qu'il n'y avait pas de conversion, car des informations pourraient être perdues, alors comment se fait-il que le casting fonctionne?
SexyBeast
8
1. J'ai utilisé la calculatrice Windows, qui utilise jusqu'à 34 chiffres. 2. J'ai dit qu'il n'y avait pas de conversion implicite . Un cast est une conversion explicite, vous indiquez donc explicitement au compilateur que vous voulez la conversion, et cela est autorisé.
Jeffrey Sax
Intéressant ... J'espère que vous surveillez toujours ce message. Je me suis familiarisé avec les suffixes après avoir rencontré «m» précédemment pour le webcast que je visionnais. Comment avez-vous fait en sorte que la calculatrice Windows affiche .58 comme valeur flottante? J'ai essayé quelques boutons qui semblaient forcer cela, mais non ... j'ai continué à obtenir 0,58. Je dois respecter un homme qui connaît si bien ses outils ...
user1585204
Je comprends tout le truc F pour float mais pourquoi? Lorsque vous avez déclaré que la variable est déclarée comme un flottant, alors lors de la compilation, elle doit savoir que cette valeur est un flottant. Et quand vous déclarez une double même chose. Cela n'a pas de sens car vous avez float myvalue = 2.4; maintenant, une fois compilé, le compilateur devrait déjà savoir que float est le type de variable. Est-ce que je manque quelque chose? Merci!
Frank G.
@FrankG. Deux raisons: 1. L'expression 2.4est interprétée comme un double partout ailleurs. 2. Les conversions de rétrécissement implicites (comme de double à float) ne sont pas autorisées. Si vous souhaitez faire une exception à ces règles, vous devez avoir une très bonne raison. Il est peu probable que l'enregistrement d'un coup de touche soit suffisant.
Jeffrey Sax
36

Parce qu'il ya plusieurs types numériques que le compilateur peut utiliser pour représenter la valeur 0.58: float, doubleet decimal. Sauf si vous êtes d'accord avec le compilateur qui en choisit un pour vous, vous devez lever l'ambiguïté.

La documentation pour doubleindique que si vous ne spécifiez pas vous-même le type, le compilateur choisit toujours doublecomme type de tout littéral numérique réel:

Par défaut, un littéral numérique réel sur le côté droit de l'opérateur d'affectation est traité comme double. Cependant, si vous voulez qu'un nombre entier soit traité comme double, utilisez le suffixe d ou D.

L'ajout du suffixe fcrée un float; le suffixe dcrée un double; le suffixe mcrée un decimal. Tous ces éléments fonctionnent également en majuscules.

Cependant, ce n'est toujours pas suffisant pour expliquer pourquoi cela ne compile pas:

float timeRemaining = 0.58;

La moitié manquante de la réponse est que la conversion du double 0.58vers le float timeRemainingperd potentiellement des informations, de sorte que le compilateur refuse de l'appliquer implicitement. Si vous ajoutez un cast explicite, la conversion est effectuée; si vous ajoutez le fsuffixe, aucune conversion ne sera nécessaire. Dans les deux cas, le code se compilerait alors.

Jon
la source
mais comment peut-il être un double ou une décimale si la variable est un flottant, il me manque quelque chose
Thomas
@BlazArt Oui, la phrase qui indique que le compilateur n'essaye même pas de vérifier la cible d'affectation. La raison en sera enterrée dans les choix de conception effectués par l'équipe de compilation. J'imagine qu'il vaut mieux être explicite face à une confusion possible, ou il était trop coûteux de se soucier de la mise en œuvre au lieu de simplement avoir deux règles, une pour intet une pour double.
Adam Houldsworth
@BlazArt: Je viens de terminer la réponse, veuillez jeter un œil à nouveau.
Jon
1
En ce qui concerne la perte d'informations, pouvez-vous me dire comment la distribution est réellement effectuée, par rapport au format IEEE 754 dans lequel ils sont stockés? Double a une précision plus élevée, cela signifie-t-il que le lancer du flotteur au double fonctionnera toujours, comme double a = 0.69f;?
SexyBeast
@Cupidvogel: Oui, la spécification garantit (au §6.1.2) que "les autres conversions numériques implicites ne perdent jamais aucune information", ce qui inclut entre autres la conversion floaten double.
Jon
2

Le problème est que .NET, afin de permettre l'exécution de certains types d'opérations implicites impliquant floatet double, devait soit spécifier explicitement ce qui devrait se passer dans tous les scénarios impliquant des opérandes mixtes, soit permettre des conversions implicites entre les types à effectuer dans un direction seulement; Microsoft a choisi de suivre l'exemple de Java en autorisant la direction qui favorise parfois la précision, mais sacrifie souvent l'exactitude et crée généralement des tracas.

Dans presque tous les cas, prendre la doublevaleur la plus proche d'une quantité numérique particulière et l'assigner à a floatdonnera la floatvaleur la plus proche de cette même quantité. Il existe quelques cas de coin, tels que la valeur 9 007 199 791 611 905; la meilleure floatreprésentation serait 9 007 200 328 482 816 (ce qui est décalé de 536 870 911), mais la conversion de la meilleure doublereprésentation (c'est-à-dire 9 007 199 791 611 904) floatdonne 9 007 199 254 740 992 (qui est décalé de 536 870 913). En général, cependant, convertir la meilleure doublereprésentation d'une certaine quantité en floatproduira soit la meilleure floatreprésentation possible , soit l'une des deux représentations qui sont essentiellement également bonnes.

Notez que ce comportement souhaitable s'applique même aux extrêmes; par exemple, la meilleure floatreprésentation de la quantité 10 ^ 308 correspond à la floatreprésentation obtenue en convertissant la meilleure doublereprésentation de cette quantité. De même, la meilleure floatreprésentation de 10 ^ 309 correspond à la floatreprésentation obtenue en convertissant la meilleure doublereprésentation de cette quantité.

Malheureusement, les conversions dans la direction qui ne nécessite pas de conversion explicite sont rarement aussi précises. La conversion de la meilleure floatreprésentation d'une valeur en doubledonnera rarement quelque chose de particulièrement proche de la meilleure doublereprésentation de cette valeur, et dans certains cas, le résultat peut être décalé de centaines d'ordres de grandeur (par exemple, la conversion de la meilleure floatreprésentation de 10 ^ 40 en doubleproduira une valeur qui compare supérieure à la meilleure doublereprésentation de 10 ^ 300.

Hélas, les règles de conversion sont ce qu'elles sont, donc il faut vivre avec l'utilisation de typecasts et de suffixes stupides lors de la conversion de valeurs dans le sens "sûr", et faire attention aux typecasts implicites dans la direction dangereuse qui donneront souvent des résultats faux.

supercat
la source