ความแตกต่างระหว่างการใช้ CGFloat กับการลอยคืออะไร?


169

ฉันมักจะใช้ CGFloat ไปทั่วทุกที่ แต่ฉันสงสัยว่าฉันได้รับ "การแสดงที่มีประสิทธิภาพ" อย่างนี้หรือไม่ CGFloat ดูเหมือนจะเป็นอะไรที่ "หนักกว่า" ลอยกว่าใช่มั้ย ฉันควรใช้ CGFloat ในจุดใดและอะไรทำให้เกิดความแตกต่างอย่างแท้จริง

คำตอบ:


193

ตามที่ @weichsel ระบุไว้ CGFloat เป็นเพียง typedef สำหรับอย่างใดอย่างหนึ่งfloatหรือdoubleหรือคุณสามารถเห็นตัวคุณเองด้วย Command-ดับเบิลคลิกที่ "CGFloat" ใน Xcode - มันจะข้ามไปที่ส่วนหัว CGBase.h ที่กำหนด typedef วิธีการเดียวกันนี้ใช้สำหรับ NSInteger และ NSUInteger เช่นกัน

มีการแนะนำชนิดเหล่านี้เพื่อให้ง่ายต่อการเขียนโค้ดที่ทำงานได้ทั้งแบบ 32 บิตและ 64 บิตโดยไม่มีการดัดแปลง อย่างไรก็ตามหากคุณต้องการfloatความแม่นยำภายในรหัสของคุณเองคุณยังคงสามารถใช้งานได้floatถ้าต้องการ - มันจะลดขนาดหน่วยความจำลง กันไปสำหรับค่าจำนวนเต็ม

ฉันขอแนะนำให้คุณลงทุนเวลาพอเหมาะในการทำให้แอปของคุณสะอาดและลองใช้งานเช่นนี้เนื่องจาก Mac ส่วนใหญ่ตอนนี้มี CPU 64 บิตและ Snow Leopard นั้นเต็ม 64 บิตรวมถึงเคอร์เนลและแอปพลิเคชันผู้ใช้ คู่มือการเปลี่ยนผ่าน 64 บิตของ Apple สำหรับ Cocoaเป็นทรัพยากรที่มีประโยชน์


ฉันคิดว่าฉันเข้าใจแล้ว แต่ใน iPhone ดูเหมือนว่าจะไม่สำคัญใช่มั้ย

4
บน iPhone ที่เรารู้จักไม่มี แต่ก็มักจะฉลาดที่จะรหัสหลักฐานในอนาคตและเรื่องนี้จะทำให้มันง่ายที่จะนำมาใช้ใหม่ได้อย่างปลอดภัยรหัสเดียวกันสำหรับ OS X
ควินน์เทย์เลอร์

ดังนั้นคุณพูดโดยทั่วไปไม่ใช้ float หรือ double โดยตรงตั้งแต่นั้นมาคุณจะต้องเชื่อมโยงกับสถาปัตยกรรมโปรเซสเซอร์ (และฉันคิดว่า JVM รวดเร็วแก้ปัญหาเมื่อหลายปีก่อน :)) ดังนั้นสิ่งที่ปลอดภัยแบบดั้งเดิม? int?
Dan Rosenstark

9
ฉันไม่ได้บอกว่าจะไม่ใช้ดั้งเดิมโดยตรง มีหลายครั้งที่ปัญหาดั้งเดิมอาจเป็นปัญหาเช่นหากตัวแปรอาจใช้เพื่อจัดเก็บข้อมูลซึ่งอาจล้นเช่นบน 64 บิต โดยทั่วไปการใช้ typedefs ที่ขึ้นกับสถาปัตยกรรมนั้นปลอดภัยกว่าในโค้ดนั้นมีโอกาสน้อยที่จะเกิดการระเบิดในสถาปัตยกรรมที่แตกต่างกัน อย่างไรก็ตามบางครั้งการใช้ชนิด 32 บิตอาจปลอดภัยอย่างสมบูรณ์และช่วยให้คุณประหยัดหน่วยความจำ ขนาดดั้งเดิมอาจมีปัญหาน้อยกว่าใน JVM แต่ Obj-C และ C ถูกคอมไพล์และการผสมไลบรารีและโค้ด 32 และ 64 บิตเป็นปัญหาอย่างแท้จริง
Quinn Taylor

1
@QuinnTaylor คุณสามารถให้ตัวอย่างที่เป็นประโยชน์เกี่ยวกับการลอยตัวในขณะที่ CGFloat ไม่ได้? ทั้ง float และ CGFloat มีจำนวนบิต จำกัด คุณสามารถล้นทั้งสองโดยจำเป็นต้องเก็บบิตมากกว่าที่พวกเขาสามารถถือ
Pwner

76

CGFloat เป็นโฟลตปกติบนระบบ 32- บิตและเพิ่มเป็นสองเท่าในระบบ 64- บิต

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

ดังนั้นคุณจะไม่ได้รับการลงโทษใด ๆ


3
คุณใช้หน่วยความจำมากเป็นสองเท่าถ้าคุณกังวลเรื่องความจำ
ไทเลอร์

8
เฉพาะใน 64- บิตแม้ว่า
Quinn Taylor

13
ถูกต้อง iPhone OS คือ 32 บิต หากคุณคิดเกี่ยวกับเรื่องนี้ iPhone จะไม่ผลักดันขีด จำกัด 4GB RAM ที่ 32 บิตและไม่ใช้โปรเซสเซอร์ Intel (ซึ่ง 64 บิตเร็วกว่า 32 บิต) นอกจากนี้ยังใช้ Modern Runtime (ซึ่งตรงกันข้ามกับ Legacy Runtime ขนาด 32 บิตบนเดสก์ท็อป - ค้นหาดังนั้นสำหรับคำศัพท์เหล่านี้หากคุณสงสัย) ดังนั้นจึงสามารถทำทุกสิ่งได้โดยทั่วไป 64 บิต OS X บางทีสักวันหนึ่งเราจะเห็นอุปกรณ์ที่รัน iPhone OS และเป็น 64 บิต แต่ในปัจจุบันไม่มีเลย
Quinn Taylor

23
ป้อน: iPhone 5S
dgund

7
5S อยู่ใน 64 บิตครั้งล่าสุดที่ฉันเข้าร่วมการประชุม (ลอนดอน) พวกเขากล่าวว่าวิธีที่พวกเขาเรียกใช้แอพ 32 บิตบน ios7 คือการเริ่มแคชพูลที่ใช้ร่วมกันอีกครั้งในหน่วยความจำ ดังนั้นมันจึงคุ้มค่าที่จะแปลงทุกอย่างสูงสุด 64- บิต (เว้นแต่คุณต้องการสนับสนุน 5.1+ หรือ 6.0+ ยัง)
phil88530

2

ดังที่คนอื่น ๆ พูดกันว่า CGFloat นั้นเป็นแบบลอยตัวบนระบบ 32 บิตและเพิ่มเป็นสองเท่าในระบบ 64 บิต อย่างไรก็ตามการตัดสินใจที่จะทำนั้นสืบทอดมาจาก OS X ซึ่งทำขึ้นตามลักษณะการทำงานของ CPU PowerPC รุ่นแรก กล่าวอีกนัยหนึ่งคุณไม่ควรคิดว่า float นั้นใช้กับ CPU แบบ 32 บิตและ double นั้นใช้กับ CPU แบบ 64 บิต (ฉันเชื่อว่าโปรเซสเซอร์ ARM ของ Apple สามารถประมวลผลได้นานเป็นสองเท่าก่อนที่พวกเขาจะไป 64 บิต) ประสิทธิภาพหลักของการใช้งาน double คือการที่พวกเขาใช้หน่วยความจำสองเท่าและดังนั้นจึงอาจช้าลง .


2

Objective-C

จากซอร์สโค้ดพื้นฐานใน 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

ลิขสิทธิ์ (c) 2000-2011 Apple Inc.

นี่คือการทำ:

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

ที่ไหน __LP64__ระบุว่าสถาปัตยกรรมปัจจุบัน * เป็น 64 บิต

โปรดทราบว่าระบบ 32- บิตยังคงสามารถใช้ 64- บิตdoubleมันใช้เวลาประมวลผลมากกว่าดังนั้น CoreGraphics ทำสิ่งนี้เพื่อวัตถุประสงค์ในการปรับให้เหมาะสมไม่ใช่เพื่อความเข้ากันได้ ถ้าคุณไม่ได้กังวลเกี่ยวกับผลการดำเนินงาน doubleแต่มีความกังวลเกี่ยวกับความถูกต้องเพียงแค่ใช้

รวดเร็ว

ใน Swift CGFloatเป็นstructwrapper รอบ ๆ ทั้งFloatในสถาปัตยกรรม 32- บิตหรือDouble64- บิต (คุณสามารถตรวจจับสิ่งนี้ในเวลารันหรือรวบรวมด้วยCGFloat.NativeType)

จากซอร์สโค้ด CoreGraphics ในCGFloat.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

* โดยเฉพาะlongs และพอยน์LPเตอร์ ดูเพิ่มเติมที่: http://www.unix.org/version2/whatsnew/lp64_wp.html


1

แค่พูดถึงว่า - ม.ค. 2020 Xcode 11.3 / iOS13

สวิฟท์ 5

จากซอร์สโค้ด 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.