NSInteger,NSUInteger,CGFloat

前導

int:4個字節,一個字節8位,佔32位的整數
long:8個字節,佔64位的整數
(3)在int與long前加上unsigned 表示無符號
(4)float:佔32位的浮點數
(5)double:佔64位的浮點數
NSInteger、NSUInteger、CGFloat不是類,而是基本數據類型

NSInteger在32系統中就是int,在64位系統中就是long, 現在咱們的蘋果真機都是64位系統
NSUInteger在32系統中就是unsigned int,在64位系統中就是unsigned long
#if __LP64__ || 0 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
CGFloat在32位系統中就是float,在64位系統中就是double
#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 語言浮點數默認是 double 型(雙精度浮點數)的)

數後加上f字母,如 2.3f、1.0f 等此類是單精度浮點數(float) 。
數直接寫出的數字,如 2.3、1.0 等此類是 double 型的。使用double聲明的變量和常1653數版是雙精度浮點數權。使用float聲明的變量和常數是單精度浮點數。

float是32位,double是64位

float32位中,有1位符號位,8位指數位,23位尾數位
double64位中,1位符號位,11位指數位,52位尾數位
取值範圍看指數部分
float是有符號型,其中,8位指數位,28=(-128—127),因此實際的範圍是-2128—2^127,約爲-3.4E38—3.4E38
同理double範圍約是-1.7E308—1.7E308,樓主可以自己按下計算器試試看,印象深些
精度是看尾數部分
float尾數位23位,2^23=8.3E6,7位,所以不同的編譯器規定不同,有些是7位,有些8位
double尾數52位,2^52=4.5E15,15位,所以double的有效位數是15位

符號位,指數位,尾數位

在C/C++中float是32位的,double是64位的,兩者在內存中的存儲方式和能夠表示的精度均不同,目前C/C++編譯器標準都遵照IEEE制定的浮點數表示法來進行float,double運算。

無論是float還是double,在內存中的存儲主要分成三部分,分別是:

(1)符號位(Sign):0代表正數,1代表負數

(2)指數位(Exponent):用於存儲科學計數法中的指數部分,並且採用移位存儲(127+指數)的二進制方式。

(3)尾數位(Mantissa):用於存儲尾數部分

對於兩者在內存中的存儲結構,如下圖所示
數字float 9.125在十進制中用科學計算的方式表示爲9.125*10^0 ,但是在計算機中,計算機只認識0和1,所以在計算機中是按照科學計算的二進制的方式表示的:

9的二進制表示爲1001
0.125的二進制表示爲0.001
所以91.25的表示成1001.001 將其表示成二進制的科學計數方式爲 1.001001*2^3

在計算機中,任何一個數都可以表示成1.xxxxxx*2^n 這樣的形式,
其中xxxxx就表示尾數部分,n表示指數部分

其中,因爲最高位橙色的1這裏,由於任何的一個數表示成這種形式時這裏都是1,所以在存儲時實際上並不保存這一位,這使得float的23bit的尾數可以表示24bit的精度,double中52bit的尾數可以表達53bit的精度。

對於float型數據,可以精確到小數點後幾位呢?當然,學過c的同學會說float能夠精確到小數點後6位,但這是怎麼的來的呢?下面做一點解釋:

十進制中的9,在二進制中的表示形式是1001,這裏也就告訴我們,表示十進制中的一位數(0到9)在二進制中需要4bit,所以我們現在float中具有24bit的精度,所以float在十進制中具有24(bit)/4(bit/1位)=6(1位),所以在十進制裏,float能夠精確到小數點後6位。同理,具有53bit精度的double類型能夠精確到小數點後13位。

對於float類型,他的指數部分有8bit,可以表示-127~128,但是這裏採用了移位存儲的方式(對這個概念不太清楚),在存儲指數時數據的基數是127,而不是0,。例如上面的9.125,其二進制的指數部分爲3,所以在存儲時實際上存的是127+3=130。(130的二進制表示爲10000010)

最終根據上面圖中float的存儲結構可以知道,實際上9.125在計算機中:

上面的二進制數轉換成十六進制後表示形式爲:01000001 00010000 00000000 00000000 --> 41 10 00 00

實際上在X86計算機中,採用的是小端存儲方式,即低地址存儲低位數據,高地址存儲高位數據。

所以數據應該是這樣存儲的:

對於double類型的存儲方式實際上和float是類似的,只是存儲的位數不同,在原理上都是一樣的。這個可以參考這篇 http://www.linuxidc.com/Linux/2012-07/65987.html 。
原文鏈接

32位與64位系統基本數據類型的字節數

不同的平臺上對不同的數據類型分配的字節數是不同的,一般的,數據類型的字節數是由編輯器決定的(編譯期間決定數據類型長度)。

簡單來說,平臺就是CPU+OS+Compiler,cpu的位是指一次性可處理的數據量是多少,1字節=8位,32位處理器可以一次性處理4個字節的數據量,依次類推。32位操作系統針對的32位的CPU設計。64位操作系統針對的64位的CPU設計。所以平臺是三者的組合,它們的字節長相同時,效率最高。
在這裏插入圖片描述

Java中的long與double的區別

long與double在java中本身都是用64位存儲的,本來用的比較簡單, 並沒有太在意一些細節,大抵就是一個存整數,一個存浮點數。
順着HBase的一個問題,查了一下stackoverflow,發現了一些比較有意思的事情。
long存的是連續的整數,而對於double,當數很大的時候,它所能表示兩個相鄰數之間的間隔就會比較大,比如long可以存9223372036854775707和9223372036854775708,而double是無法區分這兩個數的。例如:

public class Test1  
{
    public static void main(String[] args) throws Exception 
    {
        long   long1 = Long.MAX_VALUE - 100L;
        double dbl1  = long1;
        long   long2 = long1+1;
        double dbl2  = dbl1+1;
        double dbl3  = dbl2+Math.ulp(dbl2);
 
        System.out.printf("%d %d\n%f %f %f", long1, long2, dbl1, dbl2, dbl3);
    }
 
}

結果爲

9223372036854775707 9223372036854775708
9223372036854776000.000000 9223372036854776000.000000 9223372036854778000.000000

想一想,道理在計算機組成原理裏面都有,它們的編碼決定了這樣的結果。

long可以準確存儲19位數字,而double只能準備存儲16位數字。double由於有exp位,可以存16位以上的數字,但是需要以低位的不精確作爲代價。如果需要高於19位數字的精確存儲,則必須用BigInteger來保存,當然會犧牲一些性能。

總結記住
NSInteger在32系統中就是int,在64位系統中就是long, 現在咱們的蘋果真機都是64位系統
NSUInteger在32系統中就是unsigned int,在64位系統中就是unsigned long
CGFloat在32位系統中就是float,在64位系統中就是double
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章