欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言之浮點數(shù)的表示與儲存方式

 更新時間:2025年03月26日 09:46:23   作者:七月不遠(yuǎn).  
這篇文章主要介紹了C語言之浮點數(shù)的表示與儲存方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

1. 二進(jìn)制小數(shù)

1.1 十進(jìn)制小數(shù)的表示方法

理解浮點數(shù)的第一步是考慮含有小數(shù)值的十進(jìn)制數(shù)字

先來看一下十進(jìn)制數(shù)字的表示法:

其中每個十進(jìn)制數(shù) 的取值范圍是0~9。這個表達(dá)描述的數(shù)值 的定義如下:

數(shù)字權(quán)的定義與十進(jìn)制小數(shù)點符號( ‘.’ ) 相關(guān),這意味著小數(shù)點左邊的數(shù)字的權(quán)是10的正冪,得到整數(shù)值,而小數(shù)點右邊的數(shù)字的權(quán)是10的負(fù)冪,得到小數(shù)值。例如十進(jìn)制數(shù)12. 34表示數(shù)字

1.2 二進(jìn)制小數(shù)的表示方法

類比十進(jìn)制數(shù),二進(jìn)制表示小數(shù)可以用如下表示法表示,

以圖片表示為:

其中 的取值范圍是0和1。這個表達(dá)描述的數(shù)值 的定義如下:

符號 ‘ . ’ 現(xiàn)在變?yōu)榱硕M(jìn)制的點,點左邊的位的權(quán)是2的正冪,點右邊的位的權(quán)是2的負(fù)冪。例如,二進(jìn)制數(shù)101.11表示數(shù)字

2. IEEE浮點表示

2.1 IEEE浮點標(biāo)準(zhǔn)

上一節(jié)提到的定點表示法并不能很有效地表示非常大的數(shù)字。IEEE(電氣和電子工程師協(xié)會)浮點標(biāo)準(zhǔn)用如下的形式來表示一個數(shù):

在這個式子中設(shè)計三個變量,s, M以及E

符號 (sign) : s決定這數(shù)是負(fù)數(shù) (s = 1) 還是正數(shù) (s = 0)尾數(shù) (ignificand) : M是一個二進(jìn)制小數(shù)階碼 (exponent): E的作用是對浮點數(shù)加權(quán),這個權(quán)重是2的E次冪(可能是負(fù)數(shù))

例如:

5.0 化為二進(jìn)制小數(shù),由于 5.0 為正數(shù),因此 s = 0,M = 1.01,E = 2

這種標(biāo)準(zhǔn)將浮點數(shù)封裝成一種似乎很難理解的形式來存儲,但其實是相當(dāng)優(yōu)雅的。

2.2 單精度和雙精度浮點數(shù)的封裝形式

在C語言中,浮點數(shù)分為單精度浮點數(shù) float 和雙精度浮點數(shù) double,其中float在內(nèi)存中占4個字節(jié),32個比特位;double在內(nèi)存中占8個字節(jié),64個比特位。

不管是 float 還是 double ,它們都被分為三個字段,分別用來表示符號位s,階碼字段exp和編碼尾數(shù)frac。這三個字段與上述的符號s,尾數(shù)M,階碼E一一對應(yīng),但并非將s,M,E直接存入內(nèi)存,而是根據(jù)浮點數(shù)的不同數(shù)值類型按照不同的規(guī)則進(jìn)行編碼。

2.3 浮點數(shù)的數(shù)值分類

根據(jù)階碼的不同,浮點數(shù)的數(shù)值可以分為三類:

  • 規(guī)格化的值 (Normalized Values)
  • 非規(guī)格化的值 (Denormalized Values)
  • 特殊值 (Special Values)

exp的值決定了這個數(shù)屬于上面類型中的哪一種,以float類型為例:

2.3.1 規(guī)格化的值 (Normalized Values)

當(dāng)階碼域不全為0并且不全為1時,表示該數(shù)值為規(guī)格化的值

當(dāng)階碼字段不全為0時,表示該數(shù)值為非規(guī)格化的值。這是一種最普遍的情況,大多數(shù)浮點數(shù)都屬于這類。比如上一小節(jié)的5.0

對于規(guī)格化的值,在得到s, E, M之后還需要進(jìn)行一些處理才能放進(jìn)內(nèi)存:

規(guī)則1:

  • 前面已經(jīng)提到,E是階碼并且可以表示負(fù)值,存放在exp字段,但是E在標(biāo)準(zhǔn)中為無符號數(shù),這說明它不能表示負(fù)數(shù)且可表示的范圍為0~255。那么對于E為負(fù)值的情況如何處理呢?
  • 這里引入偏置 (Bias) 的概念。
  • IEEE 754規(guī)定,存入內(nèi)存時E的真實值必須再加上一個中間數(shù),對于8位的E,這個中間數(shù)是127;對于11位的E,這個中間數(shù)是1023。這里的127和1023就是Bias。也就是說,階碼的值是 E= exp - Bias
  • 例如:2^10的E是10,所以保存成32位浮點數(shù)時,必須保存成10+127=137,即10001001。此時內(nèi)存中的exp中存的是10001001。

規(guī)則2

  • 同樣的,M存放在小數(shù)字段 f 中,我們知道,當(dāng)一個小數(shù)化為二進(jìn)制小數(shù)后所得到的M總是一個介于1~2之間的值,形式為1. xxxxx
  • 因此在存數(shù)據(jù)時,考慮省略小數(shù)點前面的1(取數(shù)據(jù)的時候可以直接在前面添上),可以節(jié)省一位的存儲空間,能讓小數(shù)點后的數(shù)據(jù)多保存一位,提高數(shù)據(jù)的精度。
  • 例如,M=1.01101,存到 f 中去的數(shù)據(jù)為01101,M = 1 + f

到這里我們可以解決 5.0 這樣一個規(guī)格化的值的存放問題了:

我們知道,對于5.0來說,s = 0,M = 1.01,E = 2,

根據(jù)以上規(guī)則,在內(nèi)存中,符號位字段s = 0,階碼字段exp = E + 127 = 129 = 10000001,編碼尾數(shù)f = 01000000000000000000000(不夠23位要在后面補(bǔ)0)

結(jié)合來看:

0 10000001 01000000000000000000000,化為十六進(jìn)制為40 a0 00 00

在小端機(jī)器上的結(jié)果為:

2.3.2 非規(guī)格化的值 (Denormalized Values)

當(dāng)階碼域為全0時, 所表示的數(shù)是非規(guī)格化的值

在這種情況下,規(guī)則又有所不同:

規(guī)則1

  • 當(dāng)exp為全0時,此時的E = 1- Bias,也就是說1-127(或者1-1023)即為真實值
  • 補(bǔ)充:使階碼值為 1-Bias 仍而不是簡單的 -Bias 似乎是違反直覺的。在后面我們會知道,這種方式提供了一種從非規(guī)格化值平滑轉(zhuǎn)換到規(guī)格化值的方法

規(guī)則2

  • 有效數(shù)字M不再加上第一位的1,而是還原為0.xxxxxx的小數(shù),即M = f ,也就是小數(shù)字段的值, 不包含隱含的開頭的1
  • 實際上,如M = 1.01101,在exp = 00000000時,存進(jìn)去的是101101而不是01101

非規(guī)格化數(shù)有兩個用途:

  • 首先,它們提供了一種表示數(shù)值0 的方法,因為使用規(guī)格化數(shù),我們必須總是M>= 1,因此我們就不能表示0.0
  • 其次,非規(guī)格化數(shù)的另外一個功能是表示那些非常接近于 0.0 的數(shù)。它們提供了一種屬性,稱為逐漸溢出(gradualunder flow) ,其中,可能的數(shù)值分布均勻地接近于0.0

2.3.3 特殊值 (Special Values)

當(dāng)階碼域為全1時, 所表示的數(shù)是特殊值

特殊值可分為兩種:

1. 當(dāng)小數(shù)域全為0 時,得到的值表示無窮,當(dāng) s = 0 時,是+∞, 或者當(dāng) s = 1時,是 -∞

2.當(dāng)小數(shù)域為非零時, 結(jié)果值被稱為 “NaN”(Not a Number)。一些運(yùn)算的結(jié)果不能是實數(shù)或無窮, 就會返回這樣的NaN值

3. 數(shù)字示例

為了更加直觀地理解,我們用一個8位浮點數(shù)的例子,假定符號位 s 的長度為1,階碼字段的長度為4,小數(shù)字段的長度為3:

對于非規(guī)格數(shù):

對于規(guī)格數(shù)

可以看到,從最大非規(guī)格數(shù)0 0000 111到最小規(guī)格數(shù)0 0001 000這樣的過渡是很自然的,體現(xiàn)出了上述IEEE標(biāo)準(zhǔn)的邏輯性與和諧的美感

4. 舍入

因為表示方法限制了浮點數(shù)的范圍和精度, 所以浮點運(yùn)算只能近似地表示實數(shù)運(yùn)算

我們企圖找到一個與值 最相近的值匹配值 來作為儲存的值

例如

如果由于表示方法的限制,1.5這樣一個值無法完全放在內(nèi)存中,需要舍掉小數(shù)點后的值,那么舍入結(jié)果是1還是2呢?

IEEE定義了四種舍入方式:

  • 向偶數(shù)舍入
  • 向零舍入
  • 向上舍入
  • 向下舍入

其中,向偶數(shù)舍入(round - to - even)又被稱為向最接近的值舍入(round - to - nearest),是默認(rèn)的方式,試圖找到一個最接近的匹配值

向上和向下舍入很好理解,一個介于1~2之間的數(shù)如 1.5 向上舍入是2,向下舍入是1

向零舍入是指在在數(shù)軸上的數(shù)向 0 的方向進(jìn)行舍入,比如 1.50 向零舍入會找到 1 和 2 之間更靠近0 的數(shù) 1 ,-1.50 向零舍入會找到 -1 和 -2 之間更靠近 0 的數(shù) -1

向偶數(shù)舍入,指當(dāng)一個數(shù)是兩個可能結(jié)果的中間數(shù)時,它將數(shù)字向上或者向下舍入,使得結(jié)果的最低有效數(shù)字是偶數(shù)

比如1.50可以向1舍入,也可以向2舍入,并且正好是1和2的中間值,這時會默認(rèn)向2(偶數(shù))舍入;比如2.50可以向2舍入,也可以向3舍入,并且正好是2和3的中間值,這時同樣會向2(偶數(shù))舍入。

值得注意的是:

向偶數(shù)舍入只針對那些“中間值”。當(dāng)值為1.49或1.51時,依舊舍入為 1 和 2

方式1.401.601.502.50-1.50
向偶數(shù)舍入1222-2
向零舍入1112-1
向上舍入1112-2
向下舍入2223-1

為什么要使用向偶數(shù)舍入呢?

使用其他三種舍入方法,在一組數(shù)據(jù)中很容易引入平均值的統(tǒng)計偏差 ,當(dāng)1.50 1.60 1.70這樣一組數(shù)據(jù)都使用向上舍入,結(jié)果是2 2 2,平均值會偏大

向偶數(shù)舍入在大多數(shù)現(xiàn)實情況中避免了這種統(tǒng)計偏差。在50%的時間里,它將向上舍入,而在50%的時間里,它將向下舍入

對二進(jìn)制的浮點數(shù)舍入同樣遵循向偶數(shù)舍入的原則,并將 0 視為偶數(shù),1 視為奇數(shù)

例如:

10.11100 ,當(dāng)舍入需要精確到小數(shù)點后兩位時, 后三位100代表 ,正好是中間值,因此向偶數(shù)舍入為11.00

5. 浮點運(yùn)算

考慮下面幾個式子:

  • (1) (3.14 + 1e10) - 1e10 = 0.0
  • (2) 3.14 + (1e10 - 1e10) = 3.14
  • (3) (1e20 * 1e20) * 1e-20 = +∞
  • (4) 1e20 * (1e20 * 1e-20) = 1e20
  • (5) 1e20 * (1e20 - 1e20) = 0.0
  • (6) 1e20*1e20 - 1e20*1e20 = NaN
  • (1)(2)中,3.14 + 1e10對結(jié)果進(jìn)行了舍入,值3.14會丟失,因此對于浮點數(shù)的加法不具有結(jié)合性
  • (3)(4)中,由于計算結(jié)果可能溢出或舍入,因此浮點數(shù)的乘法也不具有結(jié)合性
  • (5)(6)中,在單精度浮點數(shù)時結(jié)果不同,說明浮點數(shù)乘法不具有分配性

6. C語言中的浮點數(shù)

所有的C語言版本提供了兩種不同的浮點數(shù)據(jù)類型: floatdouble

當(dāng)int ,float,double不同數(shù)據(jù)類型之間進(jìn)行強(qiáng)制類型轉(zhuǎn)換時,得到的結(jié)果可能會超出我們的預(yù)期,程序改變數(shù)值和位模式的原則如下( 假設(shè)int是32位的) :

  • 從 int 轉(zhuǎn)換成 float,數(shù)字不會溢出,但是可能被舍入
  • 從 int 或 float 轉(zhuǎn)換成 double,因為double有更高的精度,所以能夠保留精確的數(shù)值
  • 從 double 轉(zhuǎn)換成 float ,因為范圍要小一些,所以值可能溢出成 +∞ 或 -∞。另外,由于精確度較小,它還可能被舍入
  • 從 float 或者 double 轉(zhuǎn)換成int,值將會向零舍入。例如,1.999將被轉(zhuǎn)換成1,而-1.999將被轉(zhuǎn)換成 -1。進(jìn)一步來說,值可能會溢出

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 關(guān)于"引用"的幾點說明介紹

    關(guān)于"引用"的幾點說明介紹

    引用聲明完畢后,相當(dāng)于目標(biāo)變量名有兩個名稱,即該目標(biāo)原名稱和引用名,且不能再把該引用名作為其他變量名的別名
    2013-09-09
  • C++ 使用CRC32檢測內(nèi)存映像完整性的實現(xiàn)步驟

    C++ 使用CRC32檢測內(nèi)存映像完整性的實現(xiàn)步驟

    當(dāng)我們使用動態(tài)補(bǔ)丁的時候,那么內(nèi)存中同樣不存在校驗效果,也就無法抵御對方動態(tài)修改機(jī)器碼了,為了防止解密者直接對內(nèi)存打補(bǔ)丁,我們需要在硬盤校驗的基礎(chǔ)上,增加內(nèi)存校驗,防止動態(tài)補(bǔ)丁的運(yùn)用。
    2021-06-06
  • C++?超詳細(xì)分析多態(tài)的原理與實現(xiàn)

    C++?超詳細(xì)分析多態(tài)的原理與實現(xiàn)

    這篇文章主要介紹了C++多態(tài)的原理與實現(xiàn),多態(tài)是一種面向?qū)ο蟮脑O(shè)計思路,本身和C++不是強(qiáng)綁定的,其他語言當(dāng)中一樣有多態(tài),只不過實現(xiàn)的方式可能有所不同。下面來一起了解更多詳細(xì)內(nèi)容吧
    2022-03-03
  • C語言實現(xiàn)用?*?打印X形圖案

    C語言實現(xiàn)用?*?打印X形圖案

    這篇文章主要介紹了C語言實現(xiàn)用?*?打印X形圖案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 關(guān)于Qt?C++中connect的幾種寫法代碼示例

    關(guān)于Qt?C++中connect的幾種寫法代碼示例

    這篇文章介紹了Qt中connect函數(shù)的不同編寫方式,包括傳統(tǒng)的槽函數(shù)寫法、使用函數(shù)指針的寫法、Lambda表達(dá)式以及使用QOverload選擇重載信號的寫法,每種寫法都有其特點和適用場景,程序員應(yīng)根據(jù)具體需求選擇最合適的方式,需要的朋友可以參考下
    2024-11-11
  • C/C++中字符串流詳解及其作用介紹

    C/C++中字符串流詳解及其作用介紹

    這篇文章主要介紹了C/C++中字符串流詳解及其作用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • C語言Easyx實現(xiàn)貪吃蛇詳解

    C語言Easyx實現(xiàn)貪吃蛇詳解

    這篇文章主要為大家詳細(xì)介紹了基于easyx的C++實現(xiàn)貪吃蛇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • 深入理解C/C++混合編程

    深入理解C/C++混合編程

    本篇文章是對C/C++混合編程進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C語言編程技巧 關(guān)于const和#define的區(qū)別心得

    C語言編程技巧 關(guān)于const和#define的區(qū)別心得

    盡量用const和inline而不用#define 這個條款最好稱為:“盡量用編譯器而不用預(yù)處理”,因為#define經(jīng)常被認(rèn)為好象不是語言本身的一部分。這是問題之一。再看下面的語句:
    2013-02-02
  • C語言 野指針與空指針專篇解讀

    C語言 野指針與空指針專篇解讀

    全網(wǎng)最接地氣的C語言野指針介紹,此處對于野指針與空指針知識點做一些簡要的介紹,作者實屬初學(xué),寫博客也是作者學(xué)習(xí)的一個過程,難免文章中有內(nèi)容理解不到位或者有不當(dāng)之處,還請朋友們不吝指正,希望大家多多給予支持,贈人玫瑰,手有余香
    2021-11-11

最新評論