2009-09-04 21 views
12

Ho visto alcuni posti online e non riesco a trovare una buona spiegazione per perché dovremmo aggiungere una F o L dopo un valore assegnato a una costante C++. Ad esempio:Perché è necessario aggiungere una L o F dopo un valore assegnato a una costante C++?

const long double MYCONSTANT = 3.0000000L; 

Qualcuno può spiegare perché è necessario? La dichiarazione del tipo non implica che il valore assegnato a MYCONSTANT sia un lungo doppio? Qual è la differenza tra la riga sopra e

const long double MYCONSTANT = 3.0000000;  // no 'L' appended 

Whew!

+0

C++ Domande frequenti: [Qual è il punto di suffissi su letterali numerici?] (Http://www.parashift.com/c++-faq-lite/numeric-literal-suffixes.html) – legends2k

+0

Possibile duplicato di [qual è il motivo per dichiarare esplicitamente L o UL per valori lunghi] (https://stackoverflow.com/questions/13134956/what-is-the-reason-for-explicitly-declaring-l-or-ul-for-long-values) –

risposta

13

Le costanti a virgola mobile hanno tipo double per impostazione predefinita in C++. Poiché uno long double è più preciso di uno double, è possibile perdere cifre significative quando le costanti long double vengono convertite in double. Per gestire queste costanti, è necessario utilizzare il suffisso L per mantenere la precisione long double. Ad esempio,

long double x = 8.99999999999999999; 
long double y = 8.99999999999999999L; 
std::cout.precision(100); 
std::cout << "x=" << x << "\n"; 
std::cout << "y=" << y << "\n"; 

L'uscita per questo codice sul mio sistema, dove double è di 64 bit e long double 96, è

x=9 
y=8.9999999999999999895916591441391574335284531116485595703125 

Quello che sta succedendo qui è che x ottiene arrotondato prima della cessione, in quanto il la costante viene convertita implicitamente in double e 8.99999999999999999 non è rappresentabile come numero in virgola mobile a 64 bit. (Si noti che la rappresentazione come long double non è completamente precisa sia. Tutte le cifre dopo la prima stringa di 9 s sono un tentativo di approssimare il numero decimale 8.99999999999999999 più fedelmente possibile utilizzando 96 bit binari.)

Nel Ad esempio, non è necessaria la costante L, poiché 3.0 è rappresentabile esattamente come double o long double. Il valore costante double viene convertito implicitamente in long double senza alcuna perdita di precisione.

Il caso con F non è così ovvio. Può aiutare con il sovraccarico, come sottolinea Zan Lynx. Non sono sicuro, ma potrebbe anche evitare alcuni sottili errori di arrotondamento (ad esempio, è possibile che la codifica come float fornisca un risultato diverso dalla codifica come double, quindi arrotondando a float).

+1

Ma il compilatore può elaborarlo dalla dichiarazione. Non è necessario inserire 'int a = 1i' o 'char a = 1c' se dico 'float a = 1.0' o 'double a = 1.0' dovrebbe essere piuttosto ovvio intendo float/double rispettivamente. –

+0

Stai chiedendo al compilatore di eseguire l'inferenza del tipo, cosa che non fa, anche per le costanti integer. Le costanti integer sono int di default. Il compilatore non ti avvisa sull'assegnazione di una costante int a un char fintanto che si trova nell'intervallo di caratteri. Potrebbe tentare di mettere in guardia per le costanti in virgola mobile, ma suppongo che le regole di conversione siano troppo complicate (i limiti dei numeri interi sono molto più semplici). –

+2

È possibile scrivere tutti i valori char come valori letterali int. Il problema con i letterali del punto di flaoting è che sono in decimale, non in binario. Pertanto anche '0.1' non si adatta a un lungo doppio. Ma dati quei vincoli, '0.1L' è un'approssimazione migliore di' 0.1'. – MSalters

13

No, la dichiarazione non implica che l'inizializzatore abbia un tipo specifico. Il tipo di inizializzazione è lo stesso, indipendentemente dal tipo di inizializzazione della variabile.

Quindi, se si inizializza uno long double, ma si utilizza un double per l'intializzazione, sarebbe piuttosto sciocco. Utilizzando il suffisso L, si dice che è un letterale a virgola mobile di tipo long double. Aggiunto a un intero letterale, direi che il tipo ha long int.

+2

Nota che per i numeri interi ci sono altre regole se hai un valore letterale esadecimale o ottale. Senza alcun suffisso, un letterale esadecimale o ottale può anche diventare senza segno se il suo valore non corrisponde a un tipo firmato corrispondente (int, unsigned int, long, unsigned long). In C++ 03, l'aggiunta di L darà anche ai letterali decimali un tipo senza segno a seconda del valore e della gamma dei tipi (lunghi, senza segno). In C++ 0x, tuttavia, i letterali decimali avranno sempre un tipo firmato, indipendentemente dal fatto che sia stato aggiunto o meno un suffisso (lungo, lungo). Abbastanza confuso penso che ... –

4

Quando esiste un valore letterale, viene considerato di un determinato tipo. 3.0 è considerato un doppio 3 è considerato un int. 3.0F lo rende in un float invece di un doppio 3.0L lo rende un doppio lungo invece di un doppio. 3L è un int lungo invece di un int.

Nota almeno in g ++ e VS08 entrambi gli esempi funzionano correttamente.

1

L'esempio non ne ha bisogno, ma la ragione principale per cui so di utilizzare i tipi espliciti sui valori letterali è di assicurarsi che venga chiamato il sovraccarico della funzione corretta.

Questo può fare una grande differenza di costruttori, sovraccarichi operatore, ecc

a volte non c'è modo conveniente per ottenere il letterale nel tipo giusto, quindi è necessario utilizzare uno static_cast o mettere un costruttore in tutto il letterale.

Problemi correlati