¿Cuál es la diferencia entre usar CGFloat y float?

169

Tiendo a usar CGFloat por todas partes, pero me pregunto si obtengo un "golpe de rendimiento" sin sentido con esto. CGFloat parece ser algo "más pesado" que flotar, ¿verdad? ¿En qué puntos debo usar CGFloat y qué hace realmente la diferencia?


fuente

Respuestas:

193

Como dijo @weichsel, CGFloat es solo un typedef para cualquiera floato double. Puede verlo usted mismo haciendo Comando haciendo doble clic en "CGFloat" en Xcode: saltará al encabezado CGBase.h donde se define typedef. El mismo enfoque se usa para NSInteger y NSUInteger también.

Estos tipos se introdujeron para facilitar la escritura de código que funciona tanto en 32 bits como en 64 bits sin modificaciones. Sin embargo, si todo lo que necesita es floatprecisión dentro de su propio código, aún puede usarlo floatsi lo desea: reducirá un poco la huella de su memoria. Lo mismo ocurre con los valores enteros.

Le sugiero que invierta el modesto tiempo requerido para limpiar su aplicación de 64 bits e intente ejecutarla como tal, ya que la mayoría de las Macs ahora tienen CPU de 64 bits y Snow Leopard es totalmente de 64 bits, incluidas las aplicaciones de kernel y de usuario. La Guía de transición de 64 bits de Apple para Cocoa es un recurso útil.

Quinn Taylor
fuente
Creo que lo entiendo ahora. Pero en el iPhone parece no importar mucho, ¿verdad?
44
En el iPhone tal como lo conocemos, no. Sin embargo, siempre es aconsejable utilizar un código a prueba de futuro, y esto facilitaría la reutilización segura del mismo código para OS X.
Quinn Taylor
Entonces, básicamente, nunca use un flotante o doble directamente desde entonces, estaría vinculado a la arquitectura del procesador (y pensé que las JVM rápidas se resolvieron hace años :)). Entonces, ¿qué primitivas son seguras? int?
Dan Rosenstark
9
No dije NUNCA use un primitivo directamente. Hay ocasiones en que las primitivas rectas pueden ser problemáticas, como si una variable pudiera ser utilizada para almacenar datos que podrían desbordarse, como en 64 bits. En general, el uso de typedefs dependientes de la arquitectura es más seguro, ya que es menos probable que el código explote en una arquitectura diferente. Sin embargo, a veces usar un tipo de 32 bits puede ser completamente seguro y ahorrarle memoria. El tamaño de las primitivas puede ser un problema menor en una JVM, pero Obj-C y C están compilados, y mezclar bibliotecas y códigos de 32 y 64 bits es realmente problemático.
Quinn Taylor el
1
@QuinnTaylor, ¿puede proporcionar un ejemplo práctico de cómo se desbordaría el flotador mientras que CGFloat no? Tanto float como CGFloat tienen un número finito de bits. Puede desbordar ambos al necesitar almacenar más bits de los que pueden contener.
Pwner
76

CGFloat es un flotante regular en sistemas de 32 bits y un doble en sistemas de 64 bits

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

Por lo tanto, no obtendrá ninguna penalización de rendimiento.

Thomas Zoechling
fuente
3
Bueno, usas el doble de memoria, si te preocupa la memoria.
Tyler
8
Sin embargo, solo en 64 bits.
Quinn Taylor el
13
Correcto, el iPhone OS es de 32 bits. Si lo piensa, el iPhone no está presionando la limitación de RAM de 4 GB de 32 bits, ni está utilizando un procesador Intel (para el cual 64 bits es más rápido que 32 bits). Además, está utilizando Modern Runtime (a diferencia del Legacy Runtime de 32 bits en el escritorio; busque SO para estos términos si tiene curiosidad) para que pueda hacer básicamente todo lo que puede hacer OS X de 64 bits. Tal vez algún día veamos un dispositivo que ejecute iPhone OS y sea de 64 bits, pero actualmente no hay ninguno.
Quinn Taylor el
23
Ingrese: el iPhone 5S
dgund
77
5S ahora está en 64 bits, la última vez que ingresé a la conferencia (Londres), dijeron que la forma en que ejecutan aplicaciones de 32 bits en ios7 es iniciar otro grupo de caché compartido en la memoria, lo que puede resultar en el uso de más memoria en general. entonces vale la pena convertir todo a 64 bits. (a menos que quiera admitir 5.1+ o 6.0+ aún)
phil88530
2

Como otros han dicho, CGFloat es flotante en sistemas de 32 bits y doble en sistemas de 64 bits. Sin embargo, la decisión de hacerlo fue heredada de OS X, donde se tomó en función de las características de rendimiento de las primeras CPU PowerPC. En otras palabras, no debe pensar que float es para CPU de 32 bits y el doble es para CPU de 64 bits. (Creo que los procesadores ARM de Apple pudieron procesar dobles mucho antes de que fueran de 64 bits). El principal golpe de rendimiento del uso de dobles es que usan el doble de memoria y, por lo tanto, podrían ser más lentos si realiza muchas operaciones de coma flotante .

usuario3259383
fuente
2

C objetivo

Del código fuente de la Fundación, en 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.

Esto esencialmente está haciendo:

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

Donde __LP64__indica si la arquitectura actual * es de 64 bits.

Tenga en cuenta que los sistemas de 32 bits aún pueden usar los de 64 bits double, solo lleva más tiempo de procesador, por lo que CoreGraphics lo hace con fines de optimización, no por compatibilidad. Si no le preocupa el rendimiento pero le preocupa la precisión, simplemente utilícelo double.

Rápido

En Swift, CGFloates una structenvoltura ya sea Floaten arquitecturas de 32 bits o Doubleen arquitecturas de 64 bits (puede detectar esto en tiempo de ejecución o compilación con CGFloat.NativeType)

Del código fuente de CoreGraphics, enCGFloat.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

* Específicamente, longsy punteros, de ahí el LP. Ver también: http://www.unix.org/version2/whatsnew/lp64_wp.html

Ben Leggiero
fuente
1

solo mencione eso: enero de 2020 Xcode 11.3 / iOS13

Swift 5

Del código fuente de 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
fuente