2009-09-04 6 views
12

Spojrzałem na kilka miejsc w Internecie i nie mogę znaleźć dobrego wyjaśnienia co do tego, dlaczego powinniśmy dołączyć F lub L po wartości przypisanej do stałej C++. Na przykład:Dlaczego musisz dołączyć L lub F po wartości przypisanej do stałej C++?

const long double MYCONSTANT = 3.0000000L; 

Czy ktoś może wyjaśnić, dlaczego jest to konieczne? Czy deklaracja typu nie sugeruje, że wartość przypisana do MYCONSTANT jest długa podwójna? Jaka jest różnica między powyższą linią a

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

Whew!

+0

C++ Najczęściej zadawane pytania: [Jaki jest sens końcówek literałów numerycznych?] (Http://www.parashift.com/c++-faq-lite/numeric-literal-suffixes.html) – legends2k

+0

Możliwy duplikat [co to jest powód do jawnego deklarowania L lub UL dla długich wartości] (https://stackoverflow.com/questions/13134956/what-is-the-reason-for-exicicitly-declaring-l-or-ul-for-long-values) –

Odpowiedz

13

Stałe zmiennoprzecinkowe mają domyślnie typ double w C++. Ponieważ long double jest bardziej precyzyjny niż double, możesz utracić znaczące cyfry, gdy stałe long double są konwertowane na double. Aby obsłużyć te stałe, należy użyć przyrostka L, aby zachować dokładność long double. Na przykład,

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

Wyjście dla tego kodu w systemie, gdzie double wynosi 64 bity i long double 96, jest

x=9 
y=8.9999999999999999895916591441391574335284531116485595703125 

Co tu się dzieje jest to, że x zostanie zaokrąglona przed przypisaniem, ponieważ stała jest niejawnie przekształcana na double, a 8.99999999999999999 nie jest reprezentowana jako liczba zmiennoprzecinkowa 64-bitowa. (Zauważ, że reprezentacja jako long double nie jest w pełni precyzyjne albo. Wszystkie cyfry po pierwszym ciągiem 9 s są próbą przybliżenia liczbę dziesiętną 8.99999999999999999 tak blisko jak to możliwe przy użyciu 96 bitów binarnych.)

w twojej Na przykład nie ma potrzeby stałej L, ponieważ 3.0 można dokładnie przedstawić jako double lub long double. Stała wartość double jest niejawnie przekształcana na long double bez utraty dokładności.

Sprawa z F nie jest tak oczywista. Może pomóc w przeciążeniu, jak zauważa Zan Lynx. Nie jestem pewien, ale może też uniknąć pewnych subtelnych błędów zaokrąglania (tzn. Jest możliwe, że kodowanie jako float da inny wynik z kodowania jako double, a następnie zaokrąglenie do float).

+1

Ale kompilator może to zrobić z deklaracji. Nie musisz wstawiać "int a = 1i" lub "char a = 1c", jeśli powiem "float a = 1.0" lub "double a = 1.0", powinno być dość oczywiste, że mam na myśli odpowiednio wartość float/double. –

+0

Zadajesz kompilatorowi polecenie wnioskowania, którego nie robi, nawet dla stałych całkowitych. Stałe całkowite są domyślnie int. Kompilator nie ostrzega o przypisaniu stałej int do znaku dopóki znajduje się w zakresie znaków. Może próbować ostrzegać o stałych zmiennoprzecinkowych, ale domyślam się, że reguły konwersji są zbyt skomplikowane (granice liczb całkowitych są znacznie prostsze). –

+2

Możesz zapisać wszystkie wartości char jako int literały. Problem z literami punktów flats jest taki, że są one dziesiętne, a nie binarne. Dlatego nawet "0,1" nie zmieści się w długim podwójnym. Ale biorąc pod uwagę te ograniczenia, "0,1L" jest lepszym przybliżeniem niż "0,1". – MSalters

13

Nie, deklaracja nie oznacza, że ​​inicjator ma określony typ. Typ inicjalizacji jest taki sam, bez względu na typ zainicjowanej zmiennej.

Tak więc, jeśli zainicjujesz long double, ale użyjesz double do intializacji, byłoby to całkiem głupie. Używając przyrostka L, mówisz, że jest to literał zmiennopozycyjny typu long double. Dołączony do liczby całkowitej, powiedziałby, że typ ma long int.

+2

Należy zauważyć, że w przypadku liczb całkowitych istnieją inne reguły, jeśli istnieje literał szesnastkowy lub ósemkowy. Bez żadnego przyrostka literka szesnastkowa lub ósemkowa może również stać się niepodpisana, jeśli jej wartość nie pasuje do odpowiadającego typu podpisu (int, unsigned int, long, unsigned long). W C++ 03, dołączenie L również da znaki dziesiętne typu unsigned, w zależności od wartości i zakresu typów (long, unsigned long). W C++ 0x jednak literały dziesiętne zawsze będą miały podpisany typ, niezależnie od tego, czy dołączono przyrostek (długi, długi). Dość mylące myślę ... –

4

Gdy istnieje wartość dosłowną, uważa się ją za określoną. 3.0 jest uważane za podwójne 3 jest uważane za int. 3.0F sprawia, że ​​jest on pływający, a nie podwójny 3.0L, co czyni go długim podwójnym zamiast podwójnym. 3L to długa int zamiast int.

Uwaga co najmniej w g ++, a VS08 oba przykłady działają dobrze.

1

Twój przykład go nie potrzebuje, ale najczęstszym powodem, dla którego wiem, że używam jawnych typów na literalnych wartościach, jest upewnienie się, że wywoływane jest prawidłowe przeciążenie funkcji.

To może sprawić dużą różnicę w konstruktorów, przeciążeniem operator itd

Czasami nie ma wygodny sposób, aby uzyskać dosłowne do prawego typu, więc trzeba użyć static_cast lub umieścić konstruktor okolice dosłowny.

Powiązane problemy