斯坦福編程范式第二課筆記(數(shù)據(jù)類型在內(nèi)存中的表示)

斯坦福編程范式第二課筆記(數(shù)據(jù)類型在內(nèi)存中的表示)

內(nèi)存的最小單位是字節(jié)灾常,一個(gè)字節(jié)等于8位(bit)夭咬,每一位要么是0要么是1链峭,也就是用二進(jìn)制來表示。

一個(gè)字節(jié)在內(nèi)存中的表示為:

image

無符號(hào)整數(shù)的表示

無符號(hào)二進(jìn)制轉(zhuǎn)成十進(jìn)制公式:

image
  • w:二進(jìn)制位的長(zhǎng)度谐算。
  • i:二進(jìn)制位從右往左開始的下標(biāo)熟尉,從0開始計(jì)數(shù)。
  • w-1:由于i是從0開始計(jì)數(shù)洲脂,所以最后一個(gè)下標(biāo)就是w-1斤儿。
  • x(i):第i位的值,要么是0要么是1恐锦。
  • 2^i:2的第i次冪往果。

例如:
無符號(hào)二進(jìn)制數(shù)10010 按照公式展開就是:

image

如果把這個(gè)數(shù)用1個(gè)字節(jié)在計(jì)算機(jī)中存儲(chǔ),內(nèi)存中就表示為:

image

不足8位踩蔚,左邊補(bǔ)0棚放。

1個(gè)字節(jié)的無符號(hào)正式能表示2^8 = 256個(gè)不同的數(shù)枚粘。能表示最大的數(shù)是8個(gè)二進(jìn)位全是1的數(shù)等于255馅闽,也就是求一個(gè)公比為2首項(xiàng)是1等比數(shù)列前8項(xiàng)和馍迄。二進(jìn)制位求和公式為(2^n) - 1福也。總結(jié)下來一個(gè)n位的二進(jìn)制數(shù)能表示最大的數(shù)是(2^n) - 1攀圈,能夠表示2^n個(gè)不同的數(shù)暴凑,之所以是2^n個(gè)不同的數(shù),是因?yàn)榭梢员硎?code>0~(2^n) - 1赘来,從0開始的所以還需要+1個(gè)長(zhǎng)度现喳。

Char在內(nèi)存中的表示

Char類型是用來存儲(chǔ)單個(gè)字符,在內(nèi)存中占用1個(gè)字節(jié)的大小犬辰,它使用8個(gè)bit來表示256個(gè)字符嗦篱。
Char類型實(shí)際存儲(chǔ)的是字符的ASCII碼,由于ASCII碼是整數(shù)幌缝。所以Char最終在內(nèi)存中是一個(gè)8bit的整型灸促。

比如字符AASCII碼是65,65 = 2^0 + 2^6涵卵,所以在內(nèi)存中的表示為:

image

char ch = 'A';
printf("%d", ch); // output is 65

Short在內(nèi)存中的表示

Short 表示的是短整型浴栽,一般占用2個(gè)字節(jié)的內(nèi)存大小。

它的取值范圍是(-2)^15~(2^15)-1包含0轿偎。最大值這里是(2^15)-1典鸡,是因?yàn)閟hort有符號(hào)位,需要用最高位(用從左到右第一位)來表示符號(hào)坏晦,0表示正數(shù)萝玷,1表示負(fù)數(shù)伊者。 最大值的二進(jìn)制表示為0111111111111111(16個(gè)二進(jìn)制位),十進(jìn)制就是(2^15)-1间护。 之所以是(2^15)-1亦渗,也是之前說的求和公式((2^n)-1

實(shí)現(xiàn)加減法

二進(jìn)制加減法和十進(jìn)制一樣汁尺,把對(duì)應(yīng)相加法精,大于1就向前進(jìn)位。例如0111 + 1 = 1000

如果想要把7和-7相加使結(jié)果等于0痴突。按照在計(jì)算機(jī)中使用二進(jìn)制的最高位來當(dāng)做符號(hào)位的搂蜓,0表示正數(shù),1表示負(fù)數(shù)辽装。那么7表示為0000111帮碰,-7就表示為1000111 。0000111 + 1000111 按照二進(jìn)制先前的加法法則得出來是1001110拾积,結(jié)果不是我們想要的0殉挽。

怎么才能讓2個(gè)二進(jìn)制數(shù)相加得到0呢?

想要得到0拓巧,就需要利用進(jìn)位斯碌,比如在11111111(8個(gè)1)的基礎(chǔ)上加1就可以得到100000000(一共9位,左邊第一位是1肛度,后面8個(gè)0) 傻唾,舍掉最左邊的那個(gè)1就得到了8個(gè)0最終結(jié)果就等于0。把原碼按位取反然后與原碼相加就可以得到全1的二進(jìn)制數(shù)承耿。比如0000111按位取反就是1111000冠骄,他們倆相加得到11111111。 再把它加1就得到最后的結(jié)果0加袋。整個(gè)過程需要3步凛辣,我們把最后兩步合并成一個(gè)步驟,也就是把按位取反和加1合并到一起锁荔,其實(shí)就是把原碼的反碼加1蟀给。如1111000加1得到1111001。最后這兩步合在一起叫做取原碼的補(bǔ)碼阳堕。最后得到的1111001就叫做0000111的補(bǔ)碼跋理。

  • 正整數(shù)的補(bǔ)碼是其本身。
  • 負(fù)整數(shù)的補(bǔ)碼是把它對(duì)應(yīng)的正整數(shù)二進(jìn)制碼按位取反恬总,也就做原碼的反碼然后再加1前普。

比如正整數(shù)7的二進(jìn)制碼是0000111,它的補(bǔ)碼還是它本身壹堰。再比如-7對(duì)應(yīng)的正整數(shù)二進(jìn)制碼是0000111拭卿,它的反碼就是1111000(把原碼按位取反)骡湖。然后再加1就得到11110011111001就是-7的補(bǔ)碼峻厚。我們?cè)俅伟?code>1111001和0000111按照二進(jìn)制加法法則相加剛好得到0响蕴。這里需要注意的是,這里左邊會(huì)產(chǎn)生一個(gè)溢出位惠桃,這個(gè)溢出位是去掉不要的浦夷,得到結(jié)果就是0。

-1的補(bǔ)碼全是1辜王,因?yàn)樗由?之后就變成了0劈狐。

計(jì)算機(jī)系統(tǒng)都是用補(bǔ)碼來表示二進(jìn)制碼,這樣的好處之一就是可以讓加減法運(yùn)算統(tǒng)一處理呐馆。

位模式拷貝

當(dāng)把char類型的變量賦值給short類型的變量時(shí)肥缔,會(huì)把char的8個(gè)bit放在short的低八位(從右往左第一個(gè)字節(jié))上。

例如:

char ch = 'A'; // 'A' ASCII:65 內(nèi)存表示為 01000001
short s = ch; // 內(nèi)存表示為 00000000 | 01000001

一個(gè)特殊的情況就是當(dāng)把一個(gè)short-1賦值給一個(gè)int變量的時(shí)候汹来,并不會(huì)得到00000000 | 00000000 | 11111111 | 11111111续膳,因?yàn)槿绻@樣的話表示的值就不是-1了。所以正確的做法就是把所有的1全部拷貝給int俗慈。
例如:

short s = -1; // 內(nèi)存表示為 11111111 | 11111111
int i = s; // 內(nèi)存表示為 11111111 | 11111111 | 11111111 | 11111111

相反如果把short類型的變量賦值給char類型的變量時(shí)姑宽,會(huì)把short的低八位(從右往左第一個(gè)字節(jié))放在char僅有的一個(gè)字節(jié)上遣耍。會(huì)把多的字節(jié)自動(dòng)剔除闺阱。
例如:

short s = 65; // 內(nèi)存表示為 00000001 | 01000001
char ch = s; // 內(nèi)存表示為 01000001

浮點(diǎn)數(shù)的表示

我們已經(jīng)知道無符號(hào)二進(jìn)制轉(zhuǎn)成十進(jìn)制公式為:

image

這里的i是從0開始的也就是從右邊的第一位是2^0,如果我們從一個(gè)負(fù)整數(shù)開始的話舵变,就會(huì)存在負(fù)整數(shù)次冪酣溃,那么也就會(huì)出現(xiàn)小數(shù)部分了。
例如有一個(gè)16位的二進(jìn)制數(shù)000000011 | 11000000 用它的前八位來表示整數(shù)部分纪隙,后八位來表示小數(shù)部分赊豌,就也可以這樣表示000000011.11000000。這樣后八位也就不再是整數(shù)次冪了绵咱,而是從左到右每一位分別是2^(-1)~2^(-8)碘饼。這個(gè)數(shù)就可以表示成:

image

這是其中一種浮點(diǎn)數(shù)表示方法,這種方法表示的浮點(diǎn)數(shù)會(huì)出現(xiàn)精度不夠悲伶,表示的數(shù)值區(qū)間比較小艾恼,所以計(jì)算機(jī)實(shí)際并沒有用該方法來表示浮點(diǎn)數(shù)。

下面這種方法就是計(jì)算機(jī)內(nèi)部真實(shí)表示浮點(diǎn)數(shù)的方法麸锉。

我們先來看下十進(jìn)制的科學(xué)計(jì)數(shù)法钠绍,用科學(xué)計(jì)數(shù)法表示123.45的話就是1.2345 * 10^2。其中1.2345 為尾數(shù)花沉,10為基數(shù)柳爽,2為指數(shù)媳握。計(jì)算機(jī)在表示浮點(diǎn)數(shù)的時(shí)候,也借用了十進(jìn)制的科學(xué)計(jì)數(shù)法的思想磷脯,只不過基數(shù)為2了蛾找。

例如1000.01 可以表示成1.00001 * 2^3,幾次冪赵誓,小數(shù)點(diǎn)就向右移動(dòng)幾位腋粥。

32位float來舉例,首位是符號(hào)位S架曹,緊跟后面8位是指數(shù)位E隘冲,最后23位稱為尾數(shù)位M

計(jì)算公式:

image
  • S:符號(hào)位

S為0時(shí)剛好是正數(shù)绑雄,為1時(shí)是負(fù)數(shù)展辞。

  • M:尾數(shù)部分

它的取值范圍是1≤M<2,取值方式是從左到右每一位分別表示的是2^-1~2^-23万牺,值就是然后對(duì)各個(gè)位的表示值求和罗珍,這里跟先前浮點(diǎn)數(shù)表示的辦法一致,都是從負(fù)整數(shù)次冪開始脚粟。由于尾數(shù)的整數(shù)部分始終都是1覆旱,所以這個(gè)1可以被省略,這樣就可以多出一位來提升精度核无。

  • E:指數(shù)部分

減去127是因?yàn)槠屏渴?27扣唱。

例如0 | 10000010 | 11110000000000000000000的每一部分別是:

  • S:0

表示整數(shù)。

  • M:11110000000000000000000

這里需要再加1团南,因?yàn)闉榱颂嵘?shù)精度省略了1噪沙,所以要加回來。所以完整的尾數(shù)部分應(yīng)該是1.1111(省略了后面的0)吐根。 2^0 + 2^-1 + 2^-2 + 2^-3 + 2^-4 = 1.9375

  • E:10000010

2^7 + 2^1 = 130

分別帶入公式得:

二進(jìn)制形式:

image

十進(jìn)制形式:

image

詳細(xì)過程:
1 * 1.1111 * 2^(130-127) => 1 * 1.1111 * 2^3 => 1 * 1111.1(幾次冪正歼,小數(shù)點(diǎn)就向右移動(dòng)幾位) => 1 * (2^3 + 2^2 + 2^1 + 2^0 + 2^-1) => 1 * (8 + 4 + 2 + 1 + 0.5) => 15.5

浮點(diǎn)數(shù)與整數(shù)相互賦值

當(dāng)我們?cè)诎迅↑c(diǎn)數(shù)與整數(shù)相互賦值的時(shí)候,并不會(huì)直接拷貝bit位拷橘,而是重新計(jì)算出在新的類型中的位模式局义。
例如:

int i = 5; // 內(nèi)存表示 00000000 | 00000000 | 00000000 | 00000101
// 重新計(jì)算5在float中的表示方式
float f = i; // 內(nèi)存表示 0 | 00000000 | 00000000000000000000101
printf("%f", f) // output is 5.0

來一點(diǎn)更刺激的!H叽萄唇!

// 2^30
int i = 1073741824; // 內(nèi)存表示 01000000 | 00000000 | 00000000 | 00000000
// 這里就不會(huì)重新計(jì)算在float中的表示方式了,而是直接把bit位拷貝過去赌厅。用float的解析方式去解析int的那塊內(nèi)存穷绵。
float f = *(float *)&i; // 內(nèi)存表示 0 | 10000000 |00000000000000000000000

// 1 * 2^(128-127) * 1 = 2
printf("%f", f) // output is 2.0

這里就不會(huì)重新計(jì)算1073741824在float中的表示方式了,而是直接把intbit位拷貝過去特愿。用float的解析方式去解析int的那塊內(nèi)存仲墨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勾缭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子目养,更是在濱河造成了極大的恐慌俩由,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件癌蚁,死亡現(xiàn)場(chǎng)離奇詭異幻梯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)努释,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門碘梢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伐蒂,你說我怎么就攤上這事煞躬。” “怎么了逸邦?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵恩沛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我缕减,道長(zhǎng)雷客,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任桥狡,我火速辦了婚禮搅裙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘总放。我一直安慰自己呈宇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布局雄。 她就那樣靜靜地躺著,像睡著了一般存炮。 火紅的嫁衣襯著肌膚如雪炬搭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天穆桂,我揣著相機(jī)與錄音宫盔,去河邊找鬼。 笑死享完,一個(gè)胖子當(dāng)著我的面吹牛灼芭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播般又,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼彼绷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼巍佑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寄悯,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤萤衰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后猜旬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脆栋,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年洒擦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椿争。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡熟嫩,死狀恐怖丘薛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情邦危,我是刑警寧澤洋侨,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站倦蚪,受9級(jí)特大地震影響希坚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜陵且,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一裁僧、第九天 我趴在偏房一處隱蔽的房頂上張望慕购。 院中可真熱鬧获洲,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忘朝。三九已至晦墙,卻和暖如春但指,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工勺良, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忙芒。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像忱嘹,于是被迫代替她去往敵國(guó)和親拘悦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容