„F” po numerze

102

Co foznaczają liczby po liczbach? Czy to z C czy Objective-C? Czy jest jakaś różnica w nie dodawaniu tego do stałej liczby?

CGRect frame = CGRectMake(0.0f, 0.0f, 320.0f, 50.0f);

Czy możesz wyjaśnić, dlaczego nie napisałbym po prostu:

CGRect frame = CGRectMake(0, 0, 320, 50);
typoneerror
źródło

Odpowiedzi:

88
CGRect frame = CGRectMake(0.0f, 0.0f, 320.0f, 50.0f);

używa stałych typu float. (Stała 0,0 zwykle deklaruje podwójną wartość w celu-C; umieszczenie f na końcu - 0,0f - deklaruje stałą jako (32-bitową) zmiennoprzecinkową).

CGRect frame = CGRectMake(0, 0, 320, 50);

używa liczb całkowitych, które zostaną automatycznie przekonwertowane na liczby zmiennoprzecinkowe.

W tym przypadku nie ma (praktycznej) różnicy między nimi.

Frank Shearar
źródło
24
Teoretycznie kompilator może nie być wystarczająco inteligentny, aby przekonwertować je na zmiennoprzecinkowe w czasie kompilacji i spowolniłby wykonywanie przy czterech konwersjach int-> float (które należą do najwolniejszych rzutów). Chociaż w tym przypadku jest to prawie nieważne, zawsze lepiej jest określić poprawnie f w razie potrzeby: w wyrażeniu stała bez odpowiedniego specyfikatora może wymusić konwersję całego wyrażenia na double, a jeśli jest w ciasnej pętli, uderzenie wydajności może być zauważalny.
Matteo Italia
60

W razie wątpliwości sprawdź wyjście asemblera. Na przykład napisz mały, minimalny fragment, np. W ten sposób

#import <Cocoa/Cocoa.h>

void test() {
  CGRect r = CGRectMake(0.0f, 0.0f, 320.0f, 50.0f);
  NSLog(@"%f", r.size.width);
}

Następnie skompiluj go do asemblera z -Sopcją.

gcc -S test.m

Zapisz wyjście assemblera w test.spliku i usuń .0fze stałych i powtórz polecenie kompilacji. Następnie zrób diffnowy test.si poprzedni. Pomyśl, że powinno to pokazać, czy są jakieś rzeczywiste różnice. Myślę, że zbyt wielu ma wizję tego, co według nich robi kompilator, ale na koniec dnia należy wiedzieć, jak zweryfikować wszelkie teorie.

epatel
źródło
11
Wyjście okazało się dla mnie identyczne, nawet bez żadnego -O. Jestem na i686-apple-darwin10-gcc-4.2.1 (GCC)
kizzx2
2
Wypróbowałem powyższy przykład z LLVM w wersji 7.0.0 (clang-700.0.65) x86_64-apple-darwin15.0.0, a pliki .out również były identyczne.
Nick
43

Czasami jest różnica.

float f = 0.3; /* OK, throw away bits to convert 0.3 from double to float */
assert ( f == 0.3 ); /* not OK, f is converted from float to double
   and the value of 0.3 depends on how many bits you use to represent it. */
assert ( f == 0.3f ); /* OK, comparing two floats, although == is finicky. */
Potatoswatter
źródło
26

Mówi komputerowi, że jest to liczba zmiennoprzecinkowa (zakładam, że mówisz tutaj o c / c ++). Jeśli po liczbie nie ma f, jest ona uważana za podwójną lub całkowitą (w zależności od tego, czy występuje ułamek dziesiętny, czy nie).

3.0f -> float
3.0 -> double
3 -> integer
NickLH
źródło
czy ta konwencja jest częścią standardu C ++, czy też można ją znaleźć w kompilatorze?
jxramos
1
O ile wiem, jest to część standardu (ktoś mnie poprawia, jeśli się mylę). Najszybszym źródłem, jakie mogłem znaleźć, jest open-std.org/jtc1/sc22/open/n2356/lex.html#lex.fcon , ale prawdopodobnie jest więcej aktualnych odniesień, jeśli chcesz ich poszukać.
NickLH
5

Literał zmiennoprzecinkowy w kodzie źródłowym jest analizowany jako double. Przypisanie go do zmiennej typu float spowoduje utratę precyzji. Duża precyzja, odrzucasz 7 cyfr znaczących. Postfiks "f" pozwala ci powiedzieć kompilatorowi: "Wiem, co robię, to jest zamierzone. Nie męcz mnie tym".

Przy okazji, szanse na wywołanie błędu nie są tak małe. Wiele programów upierało się przy nieprzemyślanym porównaniu zmiennoprzecinkowym lub zakładając, że 0.1 jest dokładnie reprezentowalna.

Hans Passant
źródło
4

To f, o czym mówisz, prawdopodobnie ma na celu poinformowanie kompilatora, że ​​działa z wartością zmiennoprzecinkową. Kiedy pominieszf , jest zwykle tłumaczone na podwójne.

Obie są liczbami zmiennoprzecinkowymi, ale a floatużywa mniej bitów (a więc mniejszych i mniej dokładnych) niż a double.

Yuri
źródło
3

To kwestia C - literały zmiennoprzecinkowe są domyślnie podwójnej precyzji (double). Dodanie sufiksu f powoduje, że są one z pojedynczą precyzją (zmiennoprzecinkowe).

Możesz użyć ints do określenia wartości tutaj iw tym przypadku nie będzie to miało znaczenia, ale używanie właściwego typu jest dobrym nawykiem - spójność jest ogólnie dobra, a jeśli będziesz musiał zmienić te wartości później, Dowie się na pierwszy rzut oka, jaki to typ.

Paul R.
źródło
2

Od C. Oznacza dosłowną stałą float. Możesz pominąć zarówno „f”, jak i „.0” i użyć liczb całkowitych w swoim przykładzie z powodu niejawnej konwersji liczb całkowitych na zmiennoprzecinkowe.

Żbik
źródło
1

Prawie na pewno pochodzi z C i odzwierciedla chęć użycia raczej typu „float” niż „double”. Jest podobny do przyrostków, takich jak L na liczbach, aby wskazać, że są to długie liczby całkowite. Możesz po prostu użyć liczb całkowitych, a kompilator przeprowadzi automatyczną konwersję w razie potrzeby (dla tego konkretnego scenariusza).

tyranid
źródło
0

Zwykle mówi kompilatorowi, że wartością jest a float, tj. Liczba zmiennoprzecinkowa. Oznacza to, że może przechowywać liczby całkowite, wartości dziesiętnych i wykładniki, np 1, 0.4albo 1.2e+22.

Wielomian
źródło