Perché la "f" è richiesta quando si dichiarano i float?


88

Esempio:

float timeRemaining = 0.58f;

Perché è frichiesto alla fine di questo numero?


4
Probabilmente, perché altrimenti verrebbe trattato come double.
Uwe Keim

2
0.58 (senza il suffisso f) è un letterale di tipo double e non si può assegnare un valore double a un float, proprio come non si può assegnare un valore int a una stringa. Tuttavia puoi assegnare un valore float a un double perché qui stai allargando (C # lo convertirà implicitamente per te poiché nessuna precisione andrà persa).
Dave New


@AVD Sebbene questo sia un duplicato, il titolo della domanda sopra non restituisce il tuo collegamento nell'elenco dei possibili duplicati. Quindi questo potrebbe aggiungere valore almeno in termini di più criteri di ricerca.
Adam Houldsworth

1
@AdamHouldsworth - tutta la strada va a double & int .
adatapost

Risposte:


98

La tua dichiarazione di un float contiene due parti:

  1. Dichiara che la variabile timeRemainingè di tipo float.
  2. Assegna il valore 0.58a questa variabile.

Il problema si verifica nella parte 2.

Il lato destro viene valutato da solo. Secondo la specifica C #, un numero contenente un punto decimale che non ha un suffisso viene interpretato come un double.

Quindi ora abbiamo un doublevalore che vogliamo assegnare a una variabile di tipo float. Per fare ciò, deve esserci una conversione implicita da doublea float. Non esiste tale conversione, perché potresti (e in questo caso lo fai) perdere informazioni durante la conversione.

Il motivo è che il valore utilizzato dal compilatore non è realmente 0,58, ma il valore a virgola mobile più vicino a 0,58, che è 0,57999999999999978655962351581366 ... per doubleed esattamente 0,579999946057796478271484375 per float.

A rigor di termini, il fnon è richiesto. Puoi evitare di dover utilizzare il fsuffisso trasmettendo il valore a float:

float timeRemaining = (float)0.58;

4
Due domande, come sei arrivato al numero '0.579999946057796478271484375' e come (float) 0.58funzionerà? Prima hai detto che non c'è conversione, perché le informazioni potrebbero essere perse, allora come mai il cast funzionerà?
SexyBeast

9
1. Ho usato la calcolatrice di Windows, che utilizza fino a 34 cifre. 2. Ho detto che non c'è conversione implicita . Un cast è una conversione esplicita, quindi stai esplicitamente dicendo al compilatore che desideri la conversione, e questo è consentito.
Jeffrey Sax

Interessante ... spero che tu stia ancora monitorando questo post. Sono stato presentato ai suffissi dopo aver incontrato "m" in precedenza per il webcast che sto visualizzando. Come hai fatto a far visualizzare alla calcolatrice di Windows .58 come valore float? Ho provato un paio di pulsanti che sembravano forzare ciò, ma no ... ho continuato a ottenere 0,58. Devo rispettare un uomo che conosce così bene i suoi strumenti ...
user1585204

Capisco l'intera faccenda di F per float, ma perché? Quando hai dichiarato la variabile viene dichiarata come float, quindi quando viene compilata dovrebbe sapere che questo valore è un float. E quando dichiari una doppia stessa cosa. Non ha senso perché hai float myvalue = 2.4; ora quando viene compilato il compilatore dovrebbe già sapere che float è il tipo di variabile. Mi sto perdendo qualcosa? Grazie!
Frank G.

@FrankG. Due ragioni: 1. L'espressione 2.4è interpretata come un doppio ovunque. 2. Le conversioni restrittive implicite (come da double a float) non sono consentite. Se vuoi fare un'eccezione a queste regole, devi avere un'ottima ragione. È probabile che il salvataggio di 1 battuta di tasto non sia sufficiente.
Jeffrey Sax

36

Poiché esistono diversi tipi numerici che il compilatore può utilizzare per rappresentare il valore 0.58: float, doublee decimal. A meno che tu non sia d'accordo con il compilatore che ne sceglie uno per te, devi disambiguare.

La documentazione per doubleafferma che se non specifichi tu stesso il tipo, il compilatore sceglie sempre doublecome tipo di qualsiasi letterale numerico reale:

Per impostazione predefinita, un valore letterale numerico reale sul lato destro dell'operatore di assegnazione viene considerato doppio. Tuttavia, se desideri che un numero intero venga trattato come doppio, utilizza il suffisso do D.

L'aggiunta del suffisso fcrea un float; il suffisso dcrea un double; il suffisso mcrea un file decimal. Tutti questi funzionano anche in maiuscolo.

Tuttavia, questo non è ancora sufficiente per spiegare perché non viene compilato:

float timeRemaining = 0.58;

La metà mancante della risposta è che la conversione da double 0.58a float timeRemainingpotenzialmente perde informazioni, quindi il compilatore si rifiuta di applicarla implicitamente. Se aggiungi un cast esplicito, viene eseguita la conversione; se aggiungi il fsuffisso, non sarà necessaria alcuna conversione. In entrambi i casi il codice verrà quindi compilato.


ma come può essere un doppio o un decimale se la variabile è un float, mi manca qualcosa
Thomas

@BlazArt Sì, la frase che afferma che il compilatore non tenta nemmeno di controllare l'obiettivo dell'assegnazione. La ragione di ciò sarà sepolta nelle scelte progettuali fatte dal team del compilatore. Immagino che sia meglio essere espliciti di fronte a una possibile confusione, o era troppo costoso preoccuparsi di implementare invece di avere solo due regole, una per inte una per double.
Adam Houldsworth

@BlazArt: Ho appena finito di trovare la risposta, per favore dai un'occhiata di nuovo.
Jon

1
Per quanto riguarda la perdita di informazioni, puoi dirmi come viene effettivamente eseguito il cast, rispetto al formato IEEE 754 in cui sono memorizzati? Il doppio ha una precisione maggiore, quindi significa che il lancio da galleggiante a doppio funzionerà sempre, come double a = 0.69f;?
SexyBeast

@Cupidvogel: Sì, la specifica garantisce (in §6.1.2) che "le altre conversioni numeriche implicite non perdono mai alcuna informazione", che tra le altre include la conversione floatin double.
Jon

2

Il problema è che .NET, per consentire l'esecuzione di alcuni tipi di operazioni implicite coinvolgenti floate double, doveva o specificare esplicitamente cosa dovrebbe accadere in tutti gli scenari che coinvolgono operandi misti oppure consentire che le conversioni implicite tra i tipi siano eseguite in uno solo direzione; Microsoft ha scelto di seguire l'esempio di Java nel consentire la direzione che occasionalmente favorisce la precisione, ma spesso sacrifica la correttezza e generalmente crea problemi.

In quasi tutti i casi, prendendo il doublevalore più vicino a una particolare quantità numerica e assegnandolo a a si floatotterrà il floatvalore più vicino a quella stessa quantità. Ci sono alcuni casi d'angolo, come il valore 9.007.199.791.611.905; la migliore floatrappresentazione sarebbe 9,007,200,328,482,816 (che è disattivata di 536,870,911), ma la migliore doublerappresentazione (cioè 9,007,199,791,611,904) a float9,007,199,254,740,992 (che è disattivata di 536,870,913). In generale, tuttavia, convertire la migliore doublerappresentazione di una certa quantità in floatprodurrà la migliore floatrappresentazione possibile o una delle due rappresentazioni che sono essenzialmente ugualmente buone.

Notare che questo comportamento desiderabile si applica anche agli estremi; per esempio, la migliore floatrappresentazione per la quantità 10 ^ 308 corrisponde alla floatrappresentazione ottenuta convertendo la migliore doublerappresentazione di quella quantità. Allo stesso modo, la migliore floatrappresentazione di 10 ^ 309 corrisponde alla floatrappresentazione ottenuta convertendo la migliore doublerappresentazione di quella quantità.

Sfortunatamente, le conversioni nella direzione che non richiede un cast esplicito raramente sono altrettanto accurate. La conversione della migliore floatrappresentazione di un valore in doubleraramente produrrà qualcosa di particolarmente vicino alla migliore doublerappresentazione di quel valore, e in alcuni casi il risultato potrebbe essere sfasato di centinaia di ordini di grandezza (ad esempio convertendo la migliore floatrappresentazione di 10 ^ 40 in doubleprodurrà un valore che confronta maggiore della migliore doublerappresentazione di 10 ^ 300.

Purtroppo, le regole di conversione sono quello che sono, quindi bisogna convivere con l'uso di stupidi typecast e suffissi quando si convertono i valori nella direzione "sicura", e fare attenzione ai typecast impliciti nella direzione pericolosa che spesso produrrà risultati fasulli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.