Jaka jest różnica między używaniem CGFloat i float?

169

Zwykle używam CGFloat wszędzie, ale zastanawiam się, czy dostanę z tym bezsensowny „hit wydajnościowy”. CGFloat wydaje się być czymś „cięższym” niż float, prawda? W których punktach powinienem używać CGFloat i co tak naprawdę robi różnicę?


źródło

Odpowiedzi:

193

Jak stwierdził @weichsel, CGFloat to tylko definicja typu dla albo floatlubdouble . Możesz się o tym przekonać, dwukrotnie klikając Command na „CGFloat” w Xcode - nastąpi przejście do nagłówka CGBase.h, w którym zdefiniowano typedef. To samo podejście jest stosowane również w przypadku NSInteger i NSUInteger.

Te typy zostały wprowadzone, aby ułatwić pisanie kodu, który działa zarówno w wersji 32-bitowej, jak i 64-bitowej bez modyfikacji. Jeśli jednak wszystko, czego potrzebujesz, to floatprecyzja we własnym kodzie, nadal możesz jej używać, floatjeśli chcesz - zmniejszy to nieco zużycie pamięci. To samo dotyczy wartości całkowitych.

Sugeruję, abyś poświęcił skromny czas potrzebny na wyczyszczenie aplikacji 64-bitowej i spróbuj uruchomić ją jako taką, ponieważ większość komputerów Mac ma teraz 64-bitowe procesory, a Snow Leopard jest w pełni 64-bitowy, w tym jądro i aplikacje użytkownika. 64-bitowy przewodnik Apple dotyczący przejścia dla kakao jest przydatnym źródłem informacji.

Quinn Taylor
źródło
Myślę, że teraz rozumiem. Ale na iPhonie wydaje się, że nie ma to większego znaczenia, prawda?
4
Na iPhone'ach, jakie znamy, nie. Jednak zawsze rozsądnie jest stosować kod przyszłościowy, a to ułatwiłoby bezpieczne ponowne użycie tego samego kodu w systemie OS X.
Quinn Taylor
więc mówisz, że w zasadzie NIGDY nie używaj wartości zmiennoprzecinkowej ani podwójnej bezpośrednio od tego czasu byłbyś przywiązany do architektury procesora (a myślałem, że szybkie maszyny JVM rozwiązane lata temu :)). Więc jakie prymitywy są bezpieczne? int?
Dan Rosenstark
9
Nie powiedziałem NIGDY bezpośrednio używaj prymitywu. Czasami proste prymitywy mogą być problematyczne, na przykład jeśli zmienna może być używana do przechowywania danych, które mogą się przepełniać, na przykład w wersji 64-bitowej. Ogólnie rzecz biorąc, używanie typów zależnych od architektury jest bezpieczniejsze, ponieważ kod jest mniej podatny na eksplozję na innej architekturze. Jednak czasami użycie typu 32-bitowego może być całkowicie bezpieczne i oszczędzić pamięć. Rozmiar prymitywów może być mniejszym problemem w JVM, ale Obj-C i C są kompilowane, a mieszanie bibliotek i kodu 32- i 64-bitowego jest rzeczywiście problematyczne.
Quinn Taylor
1
@QuinnTaylor Czy możesz podać praktyczny przykład przepełnienia float, a nie CGFloat? Zarówno float, jak i CGFloat mają skończoną liczbę bitów. Możesz przepełnić oba z nich, potrzebując przechowywać więcej bitów, niż mogą pomieścić.
Pwner
76

CGFloat jest zwykłym pływakiem w systemach 32-bitowych i podwójnym w systemach 64-bitowych

typedef float CGFloat;// 32-bit
typedef double CGFloat;// 64-bit

Więc nie otrzymasz żadnej utraty wydajności.

Thomas Zoechling
źródło
3
Cóż, zużywasz dwa razy więcej pamięci, jeśli martwisz się o pamięć.
Tyler
8
Jednak tylko w wersji 64-bitowej.
Quinn Taylor
13
Prawidłowo, iPhone OS jest 32-bitowy. Jeśli się nad tym zastanowić, iPhone nie przesuwa ograniczenia 4 GB pamięci RAM do 32-bitowego, ani nie używa procesora Intel (dla którego 64-bit jest szybszy niż 32-bitowy). Ponadto używa Modern Runtime (w przeciwieństwie do Legacy Runtime 32-bitowego na pulpicie - wearch SO dla tych terminów, jeśli jesteś ciekawy), więc może zrobić w zasadzie wszystko, co może 64-bitowy OS X. Być może kiedyś zobaczymy urządzenie z systemem operacyjnym iPhone i 64-bitowym, ale obecnie nie ma takiego.
Quinn Taylor
23
Wpisz: iPhone 5S
dgund
7
5S jest teraz w wersji 64-bitowej, kiedy ostatnio byłem na konferencji (Londyn), powiedzieli, że sposób, w jaki uruchamiają 32-bitowe aplikacje na ios7, polega na zainicjowaniu kolejnej współużytkowanej puli pamięci podręcznej w pamięci, co może skutkować ogólnym użyciem większej ilości pamięci. więc warto przekonwertować wszystko do 64-bitów. (chyba że chcesz nadal
obsługiwać 5.1+
2

Jak powiedzieli inni, CGFloat jest zmiennoprzecinkową w systemach 32-bitowych i podwójną w systemach 64-bitowych. Jednak decyzja o tym została odziedziczona po OS X, gdzie została podjęta na podstawie charakterystyk wydajności wczesnych procesorów PowerPC. Innymi słowy, nie powinieneś myśleć, że zmiennoprzecinkowy jest dla 32-bitowych procesorów, a podwójny dla 64-bitowych procesorów. (Uważam, że procesory ARM firmy Apple były w stanie przetwarzać podwojenia na długo przed ich przejściem na 64-bitowe). Głównym hitem związanym z używaniem podwójnych układów jest to, że wykorzystują dwukrotnie więcej pamięci, a zatem mogą być wolniejsze, jeśli wykonujesz wiele operacji zmiennoprzecinkowych .

user3259383
źródło
2

Cel C

Z kodu źródłowego Fundacji, w CoreGraphics ' CGBase.h:

/* Definition of `CGFLOAT_TYPE', `CGFLOAT_IS_DOUBLE', `CGFLOAT_MIN', and
   `CGFLOAT_MAX'. */

#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
# define CGFLOAT_IS_DOUBLE 1
# define CGFLOAT_MIN DBL_MIN
# define CGFLOAT_MAX DBL_MAX
#else
# define CGFLOAT_TYPE float
# define CGFLOAT_IS_DOUBLE 0
# define CGFLOAT_MIN FLT_MIN
# define CGFLOAT_MAX FLT_MAX
#endif

/* Definition of the `CGFloat' type and `CGFLOAT_DEFINED'. */

typedef CGFLOAT_TYPE CGFloat;
#define CGFLOAT_DEFINED 1

Copyright (c) 2000–2011 Apple Inc.

Zasadniczo robi to:

#if defined(__LP64__) && __LP64__
typedef double CGFloat;
#else
typedef float CGFloat;
#endif

Gdzie __LP64__ wskazuje, czy aktualna architektura * jest 64-bitowa.

Zwróć uwagę, że systemy 32-bitowe mogą nadal korzystać z 64-bitowego double, po prostu zajmuje to więcej czasu procesora, więc CoreGraphics robi to w celach optymalizacji, a nie w celu zapewnienia zgodności. Jeśli nie zależy Ci na wydajności, ale na dokładności, po prostu użyj double.

Szybki

W Swift CGFloatjest structopakowaniem Floatna architekturach 32-bitowych lub Double64-bitowych (można to wykryć w czasie wykonywania lub kompilacji za pomocąCGFloat.NativeType )

Z kodu źródłowego CoreGraphics wCGFloat.swift.gyb :

public struct CGFloat {
#if arch(i386) || arch(arm)
  /// The native type used to store the CGFloat, which is Float on
  /// 32-bit architectures and Double on 64-bit architectures.
  public typealias NativeType = Float
#elseif arch(x86_64) || arch(arm64)
  /// The native type used to store the CGFloat, which is Float on
  /// 32-bit architectures and Double on 64-bit architectures.
  public typealias NativeType = Double
#endif

* W szczególności longs i wskaźniki, stąd rozszerzenie LP. Zobacz także: http://www.unix.org/version2/whatsnew/lp64_wp.html

Ben Leggiero
źródło
1

tylko o tym wspomnę - styczeń, 2020 Xcode 11.3 / iOS13

Szybki 5

Z kodu źródłowego CoreGraphics

public struct CGFloat {
    /// The native type used to store the CGFloat, which is Float on
    /// 32-bit architectures and Double on 64-bit architectures.
    public typealias NativeType = Double
Boyan Jakimov
źródło