聊一聊定點數(shù)和浮點數(shù)的存儲方式
本文轉載自微信公眾號「編程學習基地」,作者DeRoy 。轉載本文請聯(lián)系編程學習基地公眾號。
定點數(shù)和浮點數(shù)
本文中所提到的都是基于intel x86Cpu,開發(fā)環(huán)境是基于windows 10 + vs2019。本片博客需要讀者自己明白十進制、十六進制、二進制之間的轉換,文中不會介紹轉換過程,需要了解詳細過程的情查找相關資料。
首先我們簡單的介紹一下計算機中數(shù)據(jù)存儲的基礎知識,具體內(nèi)容在大學課程《計算機組成原理》中有詳細的介紹。計算機中對數(shù)據(jù)的存儲是有兩種形式,一種是以定點數(shù)方式存儲即C/C++中的char、short、int、long、longlong,另一種就是以浮點數(shù)的方式存儲即C/C++中的float、double。
定點數(shù)中char、short、int、long、longlong存儲原理都是一樣的,只是長度不同,所以我們選取int型詳細介紹,浮點數(shù)中float、double原理也是一樣的.
其中,定點數(shù)和浮點數(shù)都是最高位表示符號位(0表示正數(shù)1表示負數(shù))其余位表示數(shù)值,字節(jié)是倒敘存數(shù)(小端模式)的也就是說高字節(jié)在左邊低字節(jié)在右邊。
定點數(shù)
定點數(shù)比較簡單,計算機中存儲的是真實值,計算機采用4字節(jié)(32位)存儲int變量,例如:int value = 1 ; 則value轉化成二進制0000 0000 0000 0000 0000 0000 0000 0001為了書寫方便我們寫成16進制形式為00 00 00 01。由于計算機是倒敘存儲所以計算機中存儲為01 00 00 00。
浮點數(shù)
下面介紹一下浮點數(shù)float存儲,C/C++中float存儲標準是基于IEEE754,具體內(nèi)容是一個數(shù)值,可以使用科學計數(shù)法方式表示,即可以寫成:
A * 2^n
其中A為尾數(shù),2為底數(shù),n為指數(shù)。
由于底數(shù)為2所以所有A都是大于1小于2,也就是都可以寫成1.xxxx*2的n次方,所以計算機為了節(jié)省空間,可以不存儲整數(shù)部分的1,因為所有的浮點數(shù)都有那個1我們轉換的時候把那個1算進去就可以了。n可以是正數(shù)也可以是負數(shù)(float需要加上127,double加上1023)。
浮點數(shù)的存儲是由符號位 (sign) + 指數(shù)位 (exponent) + 小數(shù)位 (fraction) 組成。
類型 | 符號位 | 指數(shù) | 尾數(shù) |
---|---|---|---|
Float | 1位(第31位) | 8位(第23~30位) | 23位(第0~22位) |
Double | 1位(第63位) | 11位(第52~62位) | 52位(第0~51位) |
例如:float value = 12.5 ; 那么
定點數(shù) 浮點數(shù)
小數(shù)轉二進制方法:整數(shù)部分采用除 2 取余,小數(shù)部分采用乘 2 取整法
float計算機存儲(小端模式)即00 00 48 41
double計算機存儲(小端模式)即 00 00 00 00 00 00 29 40
查看內(nèi)存驗證結果
- #include<stdio.h>
- int main()
- {
- float a = 12.5;
- float* p = &a;
- double b = 12.5;
- double* pb = &b;
- printf("%d\n", a);
- printf("%d\n", (int)a);
- printf("%d\n", *(int*)&a);
- return 0;
- }
通過斷點查看變量a,b的地址,通過地址用內(nèi)存查看器查看對應的內(nèi)存來驗證
VS2019運行至斷點時,菜單調(diào)試->窗口->內(nèi)存->內(nèi)存1
double
內(nèi)存是不會騙人的,所以結果驗證無誤
大端小端
大端模式:指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的高地址
例如:12345( 0x3039 ) 的存儲順序是 0x30、0x39
小端模式:指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的低地址
例如:12345( 0x3039 ) 的存儲順序是 0x39、0x30
判斷大小端
方法一:
- #include<stdio.h>
- int main(int argc, char *argv[])
- {
- int i = 0x12345678;
- char c = i;
- if (c == 0x78)
- {
- printf("小端\n");
- }
- else
- {
- printf("大端\n");
- }
- return 0;
- }
方法二:
- #include<stdio.h>
- int main(void)
- {
- int a = 0x12345678;
- char *p = (char *)&a;
- if (0x78 == *p)
- {
- printf("小端\n");
- }
- else
- {
- printf("大端\n");
- }
- return 0;
- }
方法三:
- #include<stdio.h>
- typedef union NODE
- {
- int i;
- char c;
- }Node;
- int main(int argc, char *argv[])
- {
- Node node;
- node.i = 0x12345678;
- if (0x78 == node.c)
- {
- printf("小端\n");
- }
- else
- {
- printf("大端\n");
- }
- return 0;
- }
上期第四題
- #include<stdio.h>
- int main()
- {
- float a = 12.5;
- printf("%d\n", a);
- printf("%d\n", (int)a);
- printf("%d\n", *(int*)&a);
- return 0;
- }
- printf("%d\n", a);
printf由于類型不匹配,所以,會把float直接轉成double,double 8字節(jié),12.5f轉成十六進制:0x4029 0000 000 00000
計算機(小端模式下)存儲的值為:00 00 00 00 00 00 29 40
而我們的%d要求是一個4字節(jié)的int,對于double的內(nèi)存布局,我們可以看到前四個字節(jié)是00,所以輸出自然是0了。
- printf("%d\n", (int)a);
float強轉成int,省略掉小數(shù)部分,所有為12
- printf("%d\n", (int)&a);
float 4個字節(jié),12.5f轉成二進制是:0100 0001 0100 1000 0000 0000 0000 0000,十六進制是:0x41480000,十進制是:1095237632。
上期第10題
題目回顧:
- #include<stdio.h>
- int main()
- {
- int a = 3, b = 5;
- printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);
- //等價printf("Hello! how is this? %s\n", "super");
- printf(&a["WHAT%c%c%c %c%c %c !\n"], 1["this"], 2["beauty"], 0["tool"], 0["is"], 3["sensitive"], 4["CCCCCC"]);
- return0;
- }
指針的另類用法:
- char arr[20] = "hello world";
- printf("%s\n", arr); //從&arr[0]地址處開始讀取字符串到'\n'結束 輸出hello world
- printf("%s\n", &arr[6]); //從&arr[6]地址處開始讀取字符串到'\n'結束 輸出world
- printf("%s\n", &6[arr]); //從&arr[6]地址處開始讀取字符串到'\n'結束 輸出world
arr[i] 其實就是 *(arr+i)也就是 *(i+arr),這個屬于語法規(guī)則,只是用的少。
- printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);
- //等價printf("Hello! how is this? %s\n", "super");
在這里的"Ya!Hello! how is this? %s\n"是一個存儲在常量區(qū)的字符串
- char* p = "Ya!Hello! how is this? %s\n";
- char* p1 = "junk/super";
- printf(&a[p], &b[p1]);
- printf(&p[3], &p1[5]);
這里的數(shù)字3,5就是地址的偏移量