自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為什么 0.1 + 0.2不等于0.3?浮點(diǎn)數(shù)在計算機(jī)中是如何存儲的?

開發(fā)
本文講解了定點(diǎn)數(shù)和浮點(diǎn)數(shù),重點(diǎn)分析了浮點(diǎn)數(shù)以及IEEE 754標(biāo)準(zhǔn)下浮點(diǎn)數(shù)是如何存儲的。

為什么 0.1 + 0.2 不等于 0.3?這篇文章,我們將通過這個示例來分析浮點(diǎn)數(shù)在計算機(jī)中是如何存儲的?

一、定點(diǎn)數(shù)

1. 定義

定點(diǎn)數(shù),比較簡單,從字面上理解為小數(shù)點(diǎn)固定的數(shù)。比如,100,3.14,200.08等等都可以看成是定點(diǎn)數(shù)。

通常意義上,定點(diǎn)數(shù)表示整數(shù)或小數(shù),可以分為以下三種情況:

  • 純整數(shù):例如,400,小數(shù)點(diǎn)在最后一位,可以忽略
  • 純小數(shù):例如,0.68,小數(shù)點(diǎn)固定在最高位
  • 整數(shù)+小數(shù):例如,3.14、9.18,小數(shù)點(diǎn)在指定某個位置

接下來,我們一起看看定點(diǎn)數(shù)的十進(jìn)制和二進(jìn)制的相互轉(zhuǎn)換。

2. 十進(jìn)制整數(shù)轉(zhuǎn)二進(jìn)制

將十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制數(shù),通過不斷地除以 2,直到商為 0。步驟:

  • 將十進(jìn)制數(shù)除以2,記錄商和余數(shù)
  • 將商再次除以2,記錄新的商和余數(shù)
  • 重復(fù)這個過程,直到商為 0為止
  • 從下往上讀取所有的余數(shù),就得到了轉(zhuǎn)換后的二進(jìn)制數(shù)

比如:將十進(jìn)制的 38轉(zhuǎn)換成二進(jìn)制:

38 / 2 = 19 余 0
19 / 2 = 9  余 1
9  / 2 = 4  余 1
4  / 2 = 2  余 0
2  / 2 = 1  余 0
1  / 2 = 0  余 1

所以,(38)?? 的二進(jìn)制是 (100110)?

3. 二進(jìn)制整數(shù)轉(zhuǎn)十進(jìn)制

將二進(jìn)制數(shù)轉(zhuǎn)換為十進(jìn)制數(shù),根據(jù)權(quán)值展開法,將每一位上的數(shù)字與其對應(yīng)的權(quán)值相乘,然后將所有結(jié)果相加。權(quán)值是 2的冪,從右向左依次增加。

例如,將二進(jìn)制數(shù) 100110轉(zhuǎn)換成十進(jìn)制:

1*2? + 0*2? + 0*23 + 1*22 + 1*21 + 0*2?
= 32 + 0 + 0 + 4 + 2 + 0
= 38

所以,(100110)? 的十進(jìn)制是 (38)??

4. 十進(jìn)制小數(shù)轉(zhuǎn)二進(jìn)制

十進(jìn)制小數(shù)轉(zhuǎn)二進(jìn)制分兩部分:整數(shù)部分轉(zhuǎn)換上面已經(jīng)講解了,小數(shù)部分采用“乘2取整,從上到下順序排列”。

例如,十進(jìn)制小數(shù) 10.75 轉(zhuǎn)為二進(jìn)制小數(shù):

# 整數(shù)部分
10 / 2 = 5 余 0
5  / 2 = 2 余 1
2  / 2 = 1 余 0
1  / 2 = 0 余 1

# 小數(shù)部分
0.75 * 2 = 1.5 取整數(shù)部分 1
0.5  * 2 = 1.0 取整數(shù)部分 1

所以,(10.75)?? 的二進(jìn)制是 (1010.11)?

5 二進(jìn)制小數(shù)轉(zhuǎn)十進(jìn)制

十進(jìn)制小數(shù)轉(zhuǎn)二進(jìn)制分兩部分,整數(shù)部分轉(zhuǎn)為二進(jìn)制上面已經(jīng)講解了,小數(shù)部分采用“乘2取整,從上到下順序排列”。

例如,二進(jìn)制小數(shù)轉(zhuǎn)十進(jìn)制小數(shù):

# 整數(shù)部分
1*23 + 0*22 + 1*21 + 0*2?
= 8 + 0 + 2 + 0 + 2 + 0 = 10

# 小數(shù)部分
1*2?1 + 1*2?2
= 0.5 + 0.25
= 0.75

# 整數(shù)部分 + 小數(shù)部分
10 + 0.75 = 10.7

所以,(1010.11)? 的十進(jìn)制是 (10.75)??

6. 定點(diǎn)數(shù)的優(yōu)缺點(diǎn)

(1) 優(yōu)點(diǎn)

定點(diǎn)數(shù)的精度是固定的,可以根據(jù)需求進(jìn)行靈活調(diào)整,這使得它們在需要固定精度的應(yīng)用中非常有用。

(2) 缺點(diǎn)

定點(diǎn)數(shù)的精度是固定的,這意味著在處理大范圍或者需要高精度的數(shù)據(jù)時,可能會丟失精度或者溢出。

比如,以 1個字節(jié)(8 bit)為例,假如約定前 4位表示整數(shù)部分,后 4位表示小數(shù)部分,因此,可以表達(dá)的最大數(shù)是:(1111.1111)?=(15.9375)??。

如果想要表示更大范圍的值,怎么辦?

  • 增加 bit:比如,使用 2個字節(jié)(16 bit)、4個字節(jié)(32bit),這樣整數(shù)部分和小數(shù)部分都增加了,表示的數(shù)字范圍也變大了。
  • 小數(shù)點(diǎn)右移:小數(shù)點(diǎn)右移,整數(shù)范圍就變大了,因此整個數(shù)字范圍就變大了,但是小數(shù)部分的精度就會越來越低。

因此,對于表示大范圍或者高精度的數(shù),定點(diǎn)數(shù)存在其局限性,這時候“浮點(diǎn)數(shù)”就派上用場了。

二、IEEE 754

在講解浮點(diǎn)數(shù)之前,我們需要先了解一個很重要的標(biāo)準(zhǔn):IEEE 754,它是 20世紀(jì)80年代以來最廣泛使用的浮點(diǎn)數(shù)運(yùn)算標(biāo)準(zhǔn),為許多 CPU、浮點(diǎn)運(yùn)算器和編程語言(比如 Java)所采用。

這個標(biāo)準(zhǔn)定義了以下規(guī)范:

  • 表示浮點(diǎn)數(shù)的格式(包括負(fù)零-0)與反常值(Denormal number);
  • 一些特殊數(shù)值(無窮 Inf與非數(shù)值 NaN),以及這些數(shù)值的浮點(diǎn)數(shù)運(yùn)算;
  • 指明了四種數(shù)值修約規(guī)則和五種例外狀況(包括例外發(fā)生的時機(jī)與處理方式);

另外,在 IEEE 754標(biāo)準(zhǔn)推出之前,各個計算機(jī)公司對于浮點(diǎn)數(shù)的表示沒有一個業(yè)界通用的標(biāo)準(zhǔn),這給數(shù)據(jù)交換、計算機(jī)協(xié)同工作造成了極大不便,直到 1985年,IEEE 組織推出了 IEEE 754浮點(diǎn)數(shù)標(biāo)準(zhǔn),才結(jié)束了這混亂的局面。

三、浮點(diǎn)數(shù)

1. 什么是浮點(diǎn)數(shù)?

浮點(diǎn)數(shù),是相對定點(diǎn)數(shù)而言的,從字面上可以解釋為:小數(shù)點(diǎn)在浮動的數(shù)。在計算機(jī)科學(xué)中,浮點(diǎn)數(shù)是一種用于表示帶有小數(shù)點(diǎn)的實(shí)數(shù)的數(shù)據(jù)類型,通常采用了科學(xué)計數(shù)法表示。

如下例子,十進(jìn)制小數(shù) 300.14,用科學(xué)計數(shù)法表示,可以有多種方式,整體看上去,小數(shù)點(diǎn)好像在浮動。

300.14 = 30.014 × 101
300.14 = 3.0014 × 102
300.14 = 0.31004 × 103

在 IEEE 754標(biāo)準(zhǔn)中,浮點(diǎn)數(shù)在內(nèi)存中以二進(jìn)制形式存儲,分為四個部分:符號位、基數(shù)、指數(shù)部分和尾數(shù)部分。

  • 符號位(Sign bit):用于表示數(shù)值的正負(fù)。0表示正數(shù),1表示負(fù)數(shù)。
  • 指數(shù)部分(Exponent):用于表示數(shù)值的大小范圍。該部分存儲的是一個無符號整數(shù),通常采用偏移表示,即用實(shí)際指數(shù)加上一個固定偏移值。
  • 基數(shù)(Base):也稱為進(jìn)制或底數(shù),常見的基數(shù)包括十進(jìn)制(基數(shù)為10)、二進(jìn)制(基數(shù)為2)、八進(jìn)制(基數(shù)為8)、十六進(jìn)制(基數(shù)為16)等。
  • 尾數(shù)部分(Mantissa/Significand):用于表示數(shù)值的精度和小數(shù)部分。在IEEE 754中,尾數(shù)總是處于[1,2)之間的一個小數(shù),這樣可以省略掉小數(shù)點(diǎn)前面的 1,從而節(jié)省了一個 bit。注意:significand 和 mantissa 都是用來指代浮點(diǎn)數(shù)中的尾數(shù)部分,只不過 mantissa是早期計算機(jī)的叫法。兩個術(shù)語可以互換,用來表示浮點(diǎn)數(shù)中的尾數(shù)部分。

下圖以 300.14為例展示了一個浮點(diǎn)數(shù)的構(gòu)成:

2. 浮點(diǎn)數(shù)的精度

在IEEE 754標(biāo)準(zhǔn)中規(guī)定了 4種主要的浮點(diǎn)數(shù)類型:單精度浮點(diǎn)數(shù)(float)、雙精度浮點(diǎn)數(shù)(double)、延伸單精確度以及延伸雙精確度。

(1) 單精度浮點(diǎn)數(shù)(float)

單精度浮點(diǎn)數(shù)占用 32位(4個字節(jié)),其中,符號占 1位,指數(shù)部分占 8位,尾數(shù)部分占 23位。指數(shù)部分可以表示的范圍是 0~255,因?yàn)榇嬖谄屏?,因此指?shù)的實(shí)際范圍是從-126~+127,即 2?12?~212?,轉(zhuǎn)換成十進(jìn)制,范圍大約為 ±3.4x10?3? 到 ±3.4x103?之間。

(2) 雙精度浮點(diǎn)數(shù)(double)

雙精度浮點(diǎn)數(shù)占用 64位(8個字節(jié)),其中,符號占 1位,指數(shù)部分占 11位,尾數(shù)部分占 52位。指數(shù)部分可以表示的范圍是 0~2047,因?yàn)榇嬖谄屏浚虼酥笖?shù)的實(shí)際范圍是從-1022~+1023,即 2?1?22~ 21?23,轉(zhuǎn)換成十進(jìn)制,范圍大約為 ±1.7x10?3?? 到 ±1.7x103??之間。

(3) 延伸單精確度

因?yàn)椴怀S?,所以本文不進(jìn)行講解。

(4) 延伸雙精確度

因?yàn)椴怀S?,所以本文不進(jìn)行講解。

關(guān)于單精度浮點(diǎn)數(shù)和雙精度浮點(diǎn)數(shù)的二進(jìn)制表示如下圖: 

在了解完定點(diǎn)數(shù)和浮點(diǎn)數(shù)的一些基本概念之后,接下來講解浮點(diǎn)數(shù)使用IEEE 754標(biāo)準(zhǔn)在內(nèi)存是如何使用二進(jìn)制存儲的, 這里是IEEE 754標(biāo)準(zhǔn)的精華部分,也是比較難理解的部分,我會通過實(shí)際的例子結(jié)合圖形進(jìn)行分析。

3. 浮點(diǎn)數(shù)的IEEE754轉(zhuǎn)換

(1)  十進(jìn)制轉(zhuǎn)二進(jìn)制

這里以十進(jìn)制轉(zhuǎn) IEEE754單精度浮點(diǎn)數(shù)并且無精度丟失為例,核心流程包含 5個步驟:

① 確認(rèn) Sign符號位

比如,19.59375的符號為 0(正數(shù)),-1.1的符號為 1(負(fù)數(shù)),將結(jié)果值(0/1)填充到二進(jìn)制的 Sign bit區(qū)域。

② 將十進(jìn)制轉(zhuǎn)成純二進(jìn)制

這個步驟,只是純粹地將十進(jìn)制轉(zhuǎn)換成二進(jìn)制。

  • 對于整數(shù)部分,通過不斷地除以 2,直到商為 0;
  • 對于小數(shù)部分,采用逐步乘 2取整,直到小數(shù)部分為 0或達(dá)到尾數(shù)所需的精度;

需要注意,對于小數(shù)部分處理結(jié)束的條件有 2個:小數(shù)部分為0 或 達(dá)到尾數(shù)所需的精度。只要滿足一個就OK,這里也是為什么小數(shù)會丟精度的關(guān)鍵所在,在下面的例子會進(jìn)行講解。

對于沒有精度丟失的轉(zhuǎn)換,結(jié)束的條件是:小數(shù)部分為 0。

比如,0.25轉(zhuǎn)成二進(jìn)制

0.25 x 2 = 0.5  0
 0.5 x 2 = 1.0  1 小數(shù)部分為0,結(jié)束

③ 標(biāo)準(zhǔn)化以確定尾數(shù)和無偏移指數(shù)

根據(jù) IEEE 754標(biāo)準(zhǔn),需要將二進(jìn)制小數(shù)點(diǎn)放在最左邊的 1 之后,比如,100.101需要左移 2位,變成 1.00101x22,無偏移指數(shù)是 2;0.0011需要右移 3位,變成 1.1x2?3,無偏移指數(shù)是 -3。

這個步驟其實(shí)就是 IEEE 754標(biāo)準(zhǔn)的一個硬性規(guī)定,解決了上面提到的浮點(diǎn)數(shù)漂浮不定的問題。

④ 確認(rèn)偏移指數(shù)

偏移指數(shù),即用無偏移指數(shù)(步驟3 產(chǎn)生的結(jié)果)加上固定的偏移值127(2?-1=127),再轉(zhuǎn)換成二進(jìn)制。

假如,無偏移指數(shù)是 4,那么,偏移指數(shù)就等于4+127=131,轉(zhuǎn)換成二進(jìn)制就是10000011,然后,將二進(jìn)制結(jié)果值10000011填充到 Exponent指數(shù)區(qū)域。

⑤ 移除尾數(shù)的前導(dǎo) 1

在步驟3中,需要將二進(jìn)制小數(shù)點(diǎn)放在最左邊的 1 之后,因此,每個小數(shù)點(diǎn)前面的值都是固定的 1(也叫做前導(dǎo) 1),在 IEEE 754標(biāo)準(zhǔn)中,會將這個前導(dǎo) 1移除,從而節(jié)省了 1個bit,再將結(jié)果值填充到二進(jìn)制的 Significand尾數(shù)區(qū)域,不足部分填 0。

比如,1.001110011 移除小數(shù)點(diǎn)前固定的 1 變成了001110011,然后將結(jié)果值001110011填充到 Significand尾數(shù)區(qū)域。

為了更好的解釋上面 5個步驟,這里以十進(jìn)制19.59375轉(zhuǎn)換成IEEE 754二進(jìn)制為例進(jìn)行講解,整個過程如下圖:

(2) 十進(jìn)制轉(zhuǎn)二進(jìn)制

這里以十進(jìn)制轉(zhuǎn) IEEE754單精度浮點(diǎn)數(shù)并且有精度丟失為例,核心流程包含 6個步驟:

① 確認(rèn) Sign符號位

比如,19.59375的符號為 0(正數(shù)),-1.1的符號為 1(負(fù)數(shù)),將結(jié)果值(0/1)填充到二進(jìn)制的 Sign bit區(qū)域。

② 將十進(jìn)制轉(zhuǎn)成純二進(jìn)制

這個步驟,只是純粹地將十進(jìn)制轉(zhuǎn)換成二進(jìn)制。

  • 對于整數(shù)部分,通過不斷地除以 2,直到商為 0;
  • 對于小數(shù)部分,采用逐步乘 2取整,直到小數(shù)部分為 0或達(dá)到所需的精度;

需要注意,對于小數(shù)部分處理結(jié)束的條件有 2個:小數(shù)部分為0 或 達(dá)到尾數(shù)所需的精度。

對于有精度丟失的轉(zhuǎn)換,結(jié)束的條件是:達(dá)到所需的精度。

比如,0.3轉(zhuǎn)成二進(jìn)制

0.3 x 2 = 0.6  0
0.6 x 2 = 1.2  1
0.2 x 2 = 0.4  0
0.4 x 2 = 0.8  0
0.8 x 2 = 1.6  1
0.6 x 2 = 1.2  1 開始進(jìn)入循環(huán),只能達(dá)到所需的精度后按需舍入結(jié)束
0.2 x 2 = 0.4  0

③ 標(biāo)準(zhǔn)化以確定尾數(shù)和無偏移指數(shù)

根據(jù) IEEE 754標(biāo)準(zhǔn),需要將二進(jìn)制小數(shù)點(diǎn)放在最左邊的 1 之后,比如,100.101需要左移 2位,變成 1.00101x22,無偏移指數(shù)是 2;0.0011需要右移 3位,變成 1.1x2?3,無偏移指數(shù)是 -3。

這個步驟其實(shí)就是 IEEE 754標(biāo)準(zhǔn)的一個硬性規(guī)定,解決了上面提到的浮點(diǎn)數(shù)漂浮不定的問題。

④ 確認(rèn)偏移指數(shù)

偏移指數(shù),即用無偏移指數(shù)(步驟3 產(chǎn)生的結(jié)果)加上固定的偏移值127(2?-1=127),再轉(zhuǎn)換成二進(jìn)制。

假如,無偏移指數(shù)是 4,那么,偏移指數(shù)就等于4+127=131,轉(zhuǎn)換成二進(jìn)制就是10000011,然后,將二進(jìn)制結(jié)果值10000011填充到 Exponent指數(shù)區(qū)域。

⑤ 移除尾數(shù)的前導(dǎo) 1

在步驟3中,需要將二進(jìn)制小數(shù)點(diǎn)放在最左邊的 1 之后,因此,每個小數(shù)點(diǎn)前面的值都是固定的 1(也叫做前導(dǎo) 1),在 IEEE 754標(biāo)準(zhǔn)中,會將這個前導(dǎo) 1移除,從而節(jié)省了 1bit,再將結(jié)果值填充到二進(jìn)制的 Significand尾數(shù)區(qū)域,不足部分填0。

比如,1.001110011 移除小數(shù)點(diǎn)前固定的 1 變成了001110011,然后將結(jié)果值001110011填充到 Significand尾數(shù)區(qū)域。

⑥ 按需向上或者向下舍入

在步驟2中,小數(shù)部分轉(zhuǎn)換成二進(jìn)制的時候不是因?yàn)槌?2使得小數(shù)部分為 0結(jié)束,而是因?yàn)楫a(chǎn)生了循環(huán),導(dǎo)致達(dá)到了尾數(shù)所需的精度(單精度 23bit,雙精度 52bit),對于超出的精度范圍,需要如何處理?

答案:按需向上或者向下舍入

為了更好的解釋上面 6個步驟,這里以十進(jìn)制-123.3轉(zhuǎn)換成 IEEE 754二進(jìn)制為例進(jìn)行講解,整體流程如下圖:

注意:截圖中步驟6黃色字體1001,是指超出尾數(shù) 23bit范圍的二進(jìn)制數(shù),需要被舍入

通過上面兩個例子的分析,相信大家還是會有困惑:為什么是二進(jìn)制中存儲的是偏移指數(shù)而不是指針?為什么偏移指數(shù)是通過指數(shù)加上一個固定的偏移值?這個固定的偏移值是怎么計算的?為什么尾數(shù)需要把前導(dǎo) 1移除?IEEE 754 的舍入規(guī)則是什么?下面我們就一一解答。

(3) 二進(jìn)制轉(zhuǎn)十進(jìn)制

為了幫助大家更好地理解 IEEE 754的轉(zhuǎn)換,這里還提供了 2個 IEEE 754單精度浮點(diǎn)數(shù)二進(jìn)制轉(zhuǎn)十進(jìn)制的逆向例子,如下圖:

(4) 偏移指數(shù)

偏移指數(shù),也叫指數(shù)偏移值(exponent bias),即浮點(diǎn)數(shù)表示法中指數(shù)域的編碼值,等于指數(shù)的實(shí)際值加上某個固定的偏移值,IEEE 754標(biāo)準(zhǔn)規(guī)定該固定值偏移為2 ??1-1,其中 e為存儲指數(shù)的 bit長度,因此,單精度浮點(diǎn)數(shù)的固定偏移值是2??1-1=127,雙精度浮點(diǎn)數(shù)的固定偏移值是211?1-1=1023。

(5) 為什么需要偏移指數(shù)?

從 1.00101 x 22 和 1.1 x 2?3 可以看出來,指數(shù)有正負(fù)數(shù)的區(qū)分,即有符號的區(qū)分,因此,IEEE 754標(biāo)準(zhǔn)中的偏移指數(shù)主要解決兩個問題:

  • 表示負(fù)指數(shù):在使用二進(jìn)制表示浮點(diǎn)數(shù)的指數(shù)時,如果采用純粹的二進(jìn)制表示,那么需要額外的符號位來表示指數(shù)的正負(fù)。采用偏移指數(shù)的方式,可以將指數(shù)全部看作非負(fù)數(shù),因?yàn)閷⑵屏刻砑拥街笖?shù)部分后,所有的指數(shù)都是正數(shù),0則表示了最小的指數(shù)。
  • 排序浮點(diǎn)數(shù):使用偏移指數(shù)的方式可以更容易地對浮點(diǎn)數(shù)進(jìn)行排序。因此第 1點(diǎn)已經(jīng)把指數(shù)全部轉(zhuǎn)換成了無符號,所以,浮點(diǎn)數(shù)的比較直接變成了對二進(jìn)制的自然排序比較,不需要單獨(dú)處理符號位和指數(shù)部分的符號。

(6) 固定值偏移值如何計算?

① 單精度浮點(diǎn)數(shù)

對于單精度浮點(diǎn)數(shù),它的指數(shù)域是 8個bit,表示的有符號范圍是-127~128(-2?-1 ~ 2?),如何讓這個范圍 >=0 ?

答案:加上 127。所以,IEEE 754標(biāo)準(zhǔn)把 127設(shè)定為單精度浮點(diǎn)數(shù)的固定偏移值。

② 雙精度浮點(diǎn)數(shù)

同理,對于雙精度浮點(diǎn)數(shù),它的指數(shù)域是 11個bit,表示的有符號范圍是-1023~1024(-21?-1 ~ 21?),如何讓這個范圍 >=0 ?

答案:加上 1023。所以,IEEE 754標(biāo)準(zhǔn)把 1023設(shè)定為雙精度浮點(diǎn)數(shù)的固定偏移值。

具體信息如下圖:

(7) 為什么要移除尾數(shù)的前導(dǎo) 1?

在講解浮點(diǎn)數(shù)構(gòu)成時提過,浮點(diǎn)數(shù)的小數(shù)點(diǎn)是浮動的,因此,IEEE 754標(biāo)準(zhǔn)定義了一套固定的格式:在二進(jìn)制數(shù)中,通過移位,將小數(shù)點(diǎn)前面的值固定為 1,IEEE754 稱這種形式的浮點(diǎn)數(shù)為規(guī)范化浮點(diǎn)數(shù)。

因此,對于規(guī)范化浮點(diǎn)數(shù),既然尾數(shù)的前導(dǎo)永遠(yuǎn)是 1,那干脆不存儲,尾數(shù)其實(shí)比實(shí)際的多 1位,也就是說單精度的是 24位,雙精度是 52位。

(8) IEEE 754 的舍入規(guī)則 

關(guān)于舍入,IEEE 754標(biāo)準(zhǔn)提供了 4種方法:

① 舍入到最接近

這是 IEEE 754標(biāo)準(zhǔn)的默認(rèn)方式,將結(jié)果舍入為最接近且可以表示的值,但是當(dāng)存在兩個數(shù)一樣接近的時候,則取其中的偶數(shù)(在二進(jìn)制中是以0結(jié)尾的)。

取偶數(shù)最關(guān)鍵的步驟是找到一個中間值,先確定要保留的有效數(shù)字,找到要保留的有效數(shù)字最低位的下一位。如果這位是進(jìn)制的一半,而且之后的位數(shù)都為 0,則這個值就是中間值。

這里以二進(jìn)制為例,有效位數(shù)保留到小數(shù)點(diǎn)后 2位:

  • 10.00011,中間值為 10.00100,小于中間值,向下舍入為 10.00
  • 10.00110,中間值為 10.00100,大于中間值,向上舍入為 10.01
  • 10.11100,中間值為 10.11100,等于中間值,要保留的最低有效位 1 為奇數(shù),向上舍入為 11.00
  • 10.10100,中間值為 10.10100,等于中間值,要保留的最低有效位 0 為偶數(shù),向下舍入為 10.10

因此,上述十進(jìn)制-123.3轉(zhuǎn)換成 IEEE 754二進(jìn)制例子的舍入方式,采用向上舍入,即最后一位 +1。

② 朝 +∞方向舍入

3個要點(diǎn):

  • 正數(shù)多余位不全為 0,進(jìn)位1
  • 正數(shù)多余位全為 0,直接截尾
  • 負(fù)數(shù)直接截尾

這里以二進(jìn)制為例,有效位數(shù)保留到小數(shù)點(diǎn)后 3位:

  • 0.0011001,正數(shù),從小數(shù)點(diǎn)后 4位起,不全為0,則向上進(jìn)位(最后一位 +1),結(jié)果值為 1.010,
  • 0.0010000,正數(shù),從小數(shù)點(diǎn)后 4位起,全為0,則直接截尾(從 4位起全部舍棄),結(jié)果值為 0.001
  • -0.0011010,負(fù)數(shù)直接截尾(從 4位起全部舍棄),結(jié)果值為 -0.001

③ 朝 -∞方向舍入

3個要點(diǎn):

  • 正數(shù)直接截尾
  • 負(fù)數(shù)多余位全為0,直接截尾
  • 負(fù)數(shù)多余位不全為 0,進(jìn)位1

這里以二進(jìn)制為例,有效位數(shù)保留到小數(shù)點(diǎn)后 3位:

  • 0.0011001,正數(shù),則直接截尾(從 4位起全部舍棄),結(jié)果值為 0.001
  • -0.001000,負(fù)數(shù),從小數(shù)點(diǎn)后 4位起全為 0,則直接截尾(從 4位起全部舍棄),結(jié)果值 -0.001
  • -0.001101,負(fù)數(shù),從小數(shù)點(diǎn)后 4位起不全為 0,則向上進(jìn)位(最后一位 +1),結(jié)果值-0.010

④ 朝 0方向舍入

2個要點(diǎn):

  • 正數(shù)直接截尾
  • 負(fù)數(shù)直接截尾

數(shù)學(xué)上有 4舍5入,計算機(jī)中 0舍1入,因此,朝 0方向舍入就是直接舍棄。

這里以二進(jìn)制為例,有效位數(shù)保留到小數(shù)點(diǎn)后 3位:

  • 0.001100,正數(shù),則直接截尾(從 4位起全部舍棄)棄,結(jié)果值 0.001
  • -0.001100,負(fù)數(shù),則直接截尾(從 4位起全部舍棄)棄,結(jié)果值 -0.001

四、非規(guī)范浮點(diǎn)數(shù)

上文提到了規(guī)范化浮點(diǎn)數(shù),既然有規(guī)范化浮點(diǎn)數(shù),是不是也存在非規(guī)范化浮點(diǎn)數(shù)?非規(guī)范化浮點(diǎn)數(shù)又是什么呢?

在 IEEE 754標(biāo)準(zhǔn)中,將“指數(shù)部分全是0,尾數(shù)部分非0”這樣的浮點(diǎn)數(shù)稱為非規(guī)范化浮點(diǎn)數(shù),一般用于表示 0或者無限接近 0的很小的數(shù)字。

另外,IEEE 754標(biāo)準(zhǔn)還規(guī)定:非規(guī)范化浮點(diǎn)數(shù)的指數(shù)偏移值比規(guī)范化浮點(diǎn)數(shù)的指數(shù)偏移值小 1。

例如,最小的規(guī)范化單精度浮點(diǎn)數(shù)的指數(shù)部分編碼值為1,指數(shù)的實(shí)際值為-126;而非規(guī)范化的單精度浮點(diǎn)數(shù)的指數(shù)域編碼值為0,對應(yīng)的指數(shù)實(shí)際值也是 -126 而不是-127。實(shí)際上非規(guī)范化浮點(diǎn)數(shù)仍然是有效可以使用的,只是它們的絕對值已經(jīng)小于所有的規(guī)約浮點(diǎn)數(shù)的絕對值;即所有的非規(guī)范化浮點(diǎn)數(shù)比規(guī)約浮點(diǎn)數(shù)更接近0。規(guī)約浮點(diǎn)數(shù)的尾數(shù)大于等于1且小于2,而非規(guī)范化浮點(diǎn)數(shù)的尾數(shù)小于1且大于0。

下圖展示了非規(guī)范化單精度浮點(diǎn)數(shù)的二進(jìn)制表示:

五、特殊值

另外,IEEE 754中還定義4個特殊值,如下表:

  • 正負(fù)無窮大:指數(shù)全是 1,尾數(shù)全是 0,代表這個數(shù)是正負(fù)無窮大(±∞),正負(fù)取決于 S符號位。
  • NaN:指數(shù)全是 1,尾數(shù)非 0,代表這不是一個數(shù)字(NaN,Not a Number)。
  • 0:指數(shù)全是 0,尾數(shù)全是0,代表這個數(shù)是±0,正負(fù)取決于 S符號位。
  • 很小的值:指數(shù)全是 0,尾數(shù)不全是0,代表這個數(shù)是一個很小的非規(guī)范化浮點(diǎn)數(shù)。

六、浮點(diǎn)數(shù)的比較和運(yùn)算

有了 IEEE 754標(biāo)準(zhǔn),浮點(diǎn)數(shù)的比較就很簡單,基本上可以按照符號位、指數(shù)域、尾數(shù)域的順序作字典比較。顯然,所有正數(shù)大于負(fù)數(shù);正負(fù)號相同時,指數(shù)的二進(jìn)制表示法更大的其浮點(diǎn)數(shù)值更大。

浮點(diǎn)數(shù)的運(yùn)算和函數(shù)包含以下幾種:

  • 加減乘除(Add、subtract、multiply、divide)。在加減運(yùn)算中負(fù)零與零相等:?0.0=0.0
  • 平方根(Square root):
  • 浮點(diǎn)余數(shù)。返回值 x-(round(x/y)*y)。
  • 近似到最近的整數(shù) ?? ?? ?? ?? ??(??)。如果恰好在兩個相鄰整數(shù)之間,則近似到偶數(shù)。
  • 比較運(yùn)算. -Inf <負(fù)的規(guī)范化浮點(diǎn)數(shù)數(shù)<負(fù)的非規(guī)范化浮點(diǎn)數(shù)< -0.0 = 0.0 <正的非規(guī)范化浮點(diǎn)數(shù)<正的規(guī)范化浮點(diǎn)數(shù)< Inf;
  • 特殊比較:-Inf = -Inf, Inf = Inf, NaN與任何浮點(diǎn)數(shù)(包括自身)的比較結(jié)果都為假,即 (NaN ≠ x) = false.

七、為什么 1.0-0.9 != 0.1?

先看 Java中的一個例子:

通過運(yùn)行結(jié)果可以發(fā)現(xiàn):在 Java中,不管是單精度 float,還是雙精度 double,1.0 - 0.9 != 0.1,為什么?

從上面的講解,我們已經(jīng)知道浮點(diǎn)數(shù) IEEE 754標(biāo)準(zhǔn)在內(nèi)存中的存儲方式,這里我們再簡單的分析1.0 - 0.9場景:

1.0 可以精確轉(zhuǎn)換成IEEE 754標(biāo)準(zhǔn)二進(jìn)制為:0 01111111 00000000000000000000000

0.9 轉(zhuǎn)換成IEEE 754標(biāo)準(zhǔn)二進(jìn)制為:

符號位:0
偏移指數(shù):-1 + 127 = (126)?? = (0111 1110)?
尾數(shù):
0.9 x 2 = 1.8  1
0.8 x 2 = 1.6  1
0.6 x 2 = 1.2  1
0.2 x 2 = 0.4  0
0.4 x 2 = 0.8  0
0.8 x 2 = 1.6  1 開始進(jìn)入循環(huán),只能達(dá)到所需的精度后按需舍入結(jié)束
0.6 x 2 = 1.2  1

在0.9 轉(zhuǎn)換成 IEEE 754標(biāo)準(zhǔn)的二進(jìn)制時,出現(xiàn)了循環(huán),這樣的話,不管是單精度還是雙精度,0.9轉(zhuǎn)換成二進(jìn)制之后都有精度損失,所以,對于 float 或者 double浮點(diǎn)數(shù) 0.9,轉(zhuǎn)換后其真實(shí)值已經(jīng)不是 0.9,因此,1.0 - 0.9 != 0.1。

當(dāng)然,除了這個例子,還有很多經(jīng)典的例子,比如 w s m 為什么等于 0.30000000000000004?

八、總結(jié)

本文講解了定點(diǎn)數(shù)和浮點(diǎn)數(shù),重點(diǎn)分析了浮點(diǎn)數(shù)以及IEEE 754標(biāo)準(zhǔn)下浮點(diǎn)數(shù)是如何存儲的。

  • 浮點(diǎn)數(shù)一般用科學(xué)計數(shù)法表示
  • IEEE 754標(biāo)準(zhǔn)的浮點(diǎn)數(shù)二進(jìn)制實(shí)際包含:符號位,偏移指數(shù),尾數(shù) 3部分。
  • 十進(jìn)制小數(shù)在轉(zhuǎn)換為二進(jìn)制時,如果可以精確轉(zhuǎn)換,則不存在精度丟失。
  • 十進(jìn)制小數(shù)在轉(zhuǎn)換為二進(jìn)制時,如果無法精確轉(zhuǎn)換(存在循環(huán)或者超出尾數(shù)的范圍),則存在精度丟失的問題。
  • IEEE 754舍入規(guī)則有 4種方法:舍入到最接近、朝 +∞方向舍入、朝 -∞方向舍入以及朝 0方向舍入。
責(zé)任編輯:趙寧寧 來源: 猿java
相關(guān)推薦

2020-10-12 13:27:21

計算機(jī)瀏覽器電腦

2023-11-08 13:32:00

JavaScript浮點(diǎn)數(shù)計算

2019-10-21 11:20:12

編程小程序開發(fā)

2021-10-29 22:49:57

JavaScript開發(fā)精度

2023-05-16 17:42:04

浮點(diǎn)加法Python

2018-08-24 10:16:23

內(nèi)存浮點(diǎn)數(shù)存儲

2010-04-28 14:38:26

云計算

2022-07-14 14:27:34

Javascript數(shù)字精度二進(jìn)制

2023-06-02 13:53:56

2020-09-15 12:57:46

C 語言浮點(diǎn)數(shù)內(nèi)存

2017-06-29 08:45:06

MySQLNOT INNOT EXISTS

2012-02-03 14:39:12

Java

2015-08-12 10:04:24

2023-10-11 18:30:39

Web系統(tǒng)程序

2018-08-24 10:35:49

物理內(nèi)存存儲

2021-02-03 05:25:39

存儲層次化代碼

2021-04-15 18:09:14

存儲程序計算機(jī)

2020-10-12 06:38:08

存儲定點(diǎn)數(shù)

2021-09-06 15:29:16

大數(shù)據(jù)防疫信息安全

2021-11-15 09:32:06

浮點(diǎn)面試Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號