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

漫話:如何給女朋友解釋為什么計(jì)算機(jī)中 0.2 + 0.1 不等于 0.3 ?

開(kāi)發(fā) 前端
為什么當(dāng)我們使用電腦瀏覽器計(jì)算0.2+0.1的時(shí)候,解決卻是0.30000000000000004,而0.1+0.6的結(jié)果卻是0.7呢?

 [[345691]]

 

 

 

為什么當(dāng)我們使用電腦瀏覽器計(jì)算0.2+0.1的時(shí)候,解決卻是0.30000000000000004,而0.1+0.6的結(jié)果卻是0.7呢?

這個(gè)問(wèn)題其實(shí)一直是一個(gè)經(jīng)典的問(wèn)題,甚至有一個(gè)網(wǎng)站的域名就是https://0.30000000000000004.com/ ,主要就是解釋這個(gè)問(wèn)題的。

在這個(gè)網(wǎng)站中,列舉了各種編程語(yǔ)言中計(jì)算0.2+0.1的結(jié)果,摘選幾個(gè)如下:

 

 

 

 

可以看到,在各種語(yǔ)言中,計(jì)算0.2+0.1的結(jié)果都出奇的一致,那就是這個(gè)神奇的0.30000000000000004。

其實(shí),當(dāng)我們使用瀏覽器的控制臺(tái)(F12)進(jìn)行計(jì)算的時(shí)候,用到的就是JavaScript語(yǔ)言進(jìn)行計(jì)算的,所以,前面的現(xiàn)象,歸根結(jié)底其實(shí)和具體的編程語(yǔ)言無(wú)關(guān)。

主要問(wèn)題還是計(jì)算機(jī)中到底是如何表示小數(shù)以及如何進(jìn)行小數(shù)運(yùn)算的。

 

我們知道,計(jì)算機(jī)只認(rèn)識(shí)0和1 [為什么計(jì)算機(jī)只認(rèn)識(shí)0和1],現(xiàn)實(shí)世界中的內(nèi)容想要通過(guò)計(jì)算機(jī)存儲(chǔ)、計(jì)算或者展示,都需要轉(zhuǎn)換2進(jìn)制。在現(xiàn)實(shí)世界中,數(shù)字主要有整數(shù)和小數(shù)兩種。

在之前的[為什么計(jì)算機(jī)用補(bǔ)碼存儲(chǔ)數(shù)據(jù)]這篇文章中,我們介紹過(guò),計(jì)算機(jī)中表示整數(shù)的方式有很多,如原碼、反碼以及補(bǔ)碼等。

整數(shù)包括正整數(shù)、負(fù)整數(shù)以及零。在計(jì)算機(jī)中存儲(chǔ)的整數(shù)則分為有符號(hào)數(shù)和無(wú)符號(hào)數(shù)。

對(duì)于無(wú)符號(hào)數(shù),采用哪種編碼方式都無(wú)所謂,對(duì)于有符號(hào)數(shù)的編碼方式,常用的是補(bǔ)碼。

那么,一個(gè)十進(jìn)制數(shù)字想要獲得其二進(jìn)制的補(bǔ)碼,需要先通過(guò)一定的算法得到他對(duì)應(yīng)的原碼。

 

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

首先我們看一下,如何把十進(jìn)制整數(shù)轉(zhuǎn)換成二進(jìn)制整數(shù)?

十進(jìn)制整數(shù)轉(zhuǎn)換為二進(jìn)制整數(shù)采用"除2取余,逆序排列"法。

具體做法是:

用2整除十進(jìn)制整數(shù),可以得到一個(gè)商和余數(shù);

再用2去除商,又會(huì)得到一個(gè)商和余數(shù),如此進(jìn)行,直到商為小于1時(shí)為止

然后把先得到的余數(shù)作為二進(jìn)制數(shù)的低位有效位,后得到的余數(shù)作為二進(jìn)制數(shù)的高位有效位,依次排列起來(lái)。

如,我們想要把127轉(zhuǎn)換成二進(jìn)制,做法如下:

 


 

 

那么,十進(jìn)制小數(shù)轉(zhuǎn)換成二進(jìn)制小數(shù),又該如何計(jì)算呢?

十進(jìn)制小數(shù)轉(zhuǎn)換成二進(jìn)制小數(shù)采用"乘2取整,順序排列"法。

具體做法是:* 用2乘十進(jìn)制小數(shù),可以得到積 * 將積的整數(shù)部分取出,再用2乘余下的小數(shù)部分,又得到一個(gè)積 * 再將積的整數(shù)部分取出,如此進(jìn)行,直到積中的小數(shù)部分為零,此時(shí)0或1為二進(jìn)制的最后一位?;蛘哌_(dá)到所要求的精度為止。

 

所以,十進(jìn)制的0.625對(duì)應(yīng)的二進(jìn)制就是0.101。

 

不是所有數(shù)都能用二進(jìn)制表示

我們知道了如何將一個(gè)十進(jìn)制小數(shù)轉(zhuǎn)換成二進(jìn)制,那么是不是計(jì)算就可以直接用二進(jìn)制表示小數(shù)了呢?

前面我們的例子中0.625是一個(gè)特列,那么還是用同樣的算法,請(qǐng)計(jì)算下0.1對(duì)應(yīng)的二進(jìn)制是多少?

 

我們發(fā)現(xiàn),0.1的二進(jìn)制表示中出現(xiàn)了無(wú)限循環(huán)的情況,也就是(0.1)10 = (0.000110011001100…)2

這種情況,計(jì)算機(jī)就沒(méi)辦法用二進(jìn)制精確的表示0.1了。

也就是說(shuō),對(duì)于像0.1這種數(shù)字,我們是沒(méi)辦法將他轉(zhuǎn)換成一個(gè)確定的二進(jìn)制數(shù)的。

 

IEEE 754

為了解決部分小數(shù)無(wú)法使用二進(jìn)制精確表示的問(wèn)題,于是就有了IEEE 754規(guī)范。

IEEE二進(jìn)制浮點(diǎn)數(shù)算術(shù)標(biāo)準(zhǔn)(IEEE 754)是20世紀(jì)80年代以來(lái)最廣泛使用的浮點(diǎn)數(shù)運(yùn)算標(biāo)準(zhǔn),為許多CPU與浮點(diǎn)運(yùn)算器所采用。

浮點(diǎn)數(shù)和小數(shù)并不是完全一樣的,計(jì)算機(jī)中小數(shù)的表示法,其實(shí)有定點(diǎn)和浮點(diǎn)兩種。因?yàn)樵谖粩?shù)相同的情況下,定點(diǎn)數(shù)的表示范圍要比浮點(diǎn)數(shù)小。所以在計(jì)算機(jī)科學(xué)中,使用浮點(diǎn)數(shù)來(lái)表示實(shí)數(shù)的近似值。

IEEE 754規(guī)定了四種表示浮點(diǎn)數(shù)值的方式:?jiǎn)尉_度(32位)、雙精確度(64位)、延伸單精確度(43比特以上,很少使用)與延伸雙精確度(79比特以上,通常以80位實(shí)現(xiàn))。

其中最常用的就是32位單精度浮點(diǎn)數(shù)和64位雙精度浮點(diǎn)數(shù)。

IEEE并沒(méi)有解決小數(shù)無(wú)法精確表示的問(wèn)題,只是提出了一種使用近似值表示小數(shù)的方式,并且引入了精度的概念。

浮點(diǎn)數(shù)是一串0和1構(gòu)成的位序列(bit sequence),從邏輯上用三元組{S,E,M}表示一個(gè)數(shù)N,如下圖所示:

 

S(sign)表示N的符號(hào)位。對(duì)應(yīng)值s滿足:n>0時(shí),s=0; n≤0時(shí),s=1。

E(exponent)表示N的指數(shù)位,位于S和M之間的若干位。對(duì)應(yīng)值e值也可正可負(fù)。

M(mantissa)表示N的尾數(shù)位,恰好,它位于N末尾。M也叫有效數(shù)字位(significand)、系數(shù)位(coefficient), 甚至被稱作"小數(shù)"。

則浮點(diǎn)數(shù)N的實(shí)際值n由下方的式子表示:

 

上面這個(gè)公式看起來(lái)很復(fù)雜,其中符號(hào)位和尾數(shù)位還比較容易理解,但是這個(gè)指數(shù)位就不是那么容易理解了。

其實(shí),大家也不用太過(guò)于糾結(jié)這個(gè)公式,大家只需要知道對(duì)于單精度浮點(diǎn)數(shù),最多只能用32位字符表示一個(gè)數(shù)字,雙精度浮點(diǎn)數(shù)最多只能用64位來(lái)表示一個(gè)數(shù)字。

而對(duì)于那些無(wú)限循環(huán)的二進(jìn)制數(shù)來(lái)說(shuō),計(jì)算機(jī)采用浮點(diǎn)數(shù)的方式保留了一定的有效數(shù)字,那么這個(gè)值只能是近似值,不可能是真實(shí)值。

至于一個(gè)數(shù)對(duì)應(yīng)的IEEE 754浮點(diǎn)數(shù)應(yīng)該如何計(jì)算,不是本文的重點(diǎn),這里就不再贅述了,過(guò)程還是比較復(fù)雜的,需要進(jìn)行對(duì)階、尾數(shù)求和、規(guī)格化、舍入以及溢出判斷等。

但是這些其實(shí)不需要了解的太詳細(xì),我們只需要知道,小數(shù)在計(jì)算機(jī)中的表示是近似數(shù),并不是真實(shí)值。根據(jù)精度不同,近似程度也有所不同。

如0.1這個(gè)小數(shù),他對(duì)應(yīng)的在雙精度浮點(diǎn)數(shù)的二進(jìn)制為:0.00011001100110011001100110011001100110011001100110011001 。

0.2這個(gè)小數(shù)0.00110011001100110011001100110011001100110011001100110011 。

所以兩者相加:

 

轉(zhuǎn)換成10進(jìn)制之后得到:0.30000000000000004!

 

避免精度丟失

在Java中,使用float表示單精度浮點(diǎn)數(shù),double表示雙精度浮點(diǎn)數(shù),表示的都是近似值。

所以,在Java代碼中,千萬(wàn)不要使用float或者double來(lái)進(jìn)行高精度運(yùn)算,尤其是金額運(yùn)算,否則就很容易產(chǎn)生資損問(wèn)題。

為了解決這樣的精度問(wèn)題,Java中提供了BigDecimal來(lái)進(jìn)行精確運(yùn)算。

 

參考資料:

https://0.30000000000000004.com/

https://zh.wikipedia.org/zh-hans/IEEE_754

https://www.h-schmidt.net/FloatConverter/IEEE754.html

關(guān)于作者:漫話編程,是一個(gè)通過(guò)漫畫(huà)+音頻的形式講解枯燥的編程知識(shí)的公眾號(hào)。致力于讓編程變得更有樂(lè)趣。

本文轉(zhuǎn)載自微信公眾號(hào)「漫話編程」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系漫話編程公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: 漫話編程
相關(guān)推薦

2024-08-23 08:43:08

2023-11-08 13:32:00

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

2021-06-07 12:11:20

JavaRunning狀態(tài)

2019-10-21 11:20:12

編程小程序開(kāi)發(fā)

2021-03-02 06:03:30

Java繼承對(duì)象

2019-10-09 10:45:16

云計(jì)算Web互聯(lián)網(wǎng)

2020-03-16 14:08:59

線程熔斷限流

2019-03-12 09:43:14

反向代理正向代理服務(wù)器

2021-05-10 19:58:06

MySQLUTF-8數(shù)據(jù)庫(kù)

2021-09-14 12:00:11

VR字節(jié)跳動(dòng)

2021-04-26 14:00:43

Java 數(shù)據(jù)類型

2019-12-23 10:26:02

3PC分布式2PC

2019-04-09 09:40:23

2020-10-19 13:01:31

刪庫(kù)程序員思科

2019-07-22 10:34:31

大案牘術(shù)大數(shù)據(jù)Big Data

2019-04-26 14:46:18

GitGitHub局域網(wǎng)

2019-03-06 10:59:09

寬帶王者榮耀網(wǎng)絡(luò)

2019-04-19 09:48:53

樂(lè)觀鎖悲觀鎖數(shù)據(jù)庫(kù)

2020-12-28 12:37:36

緩存擊穿穿透

2020-03-23 12:57:20

撞庫(kù)脫庫(kù)洗庫(kù)
點(diǎn)贊
收藏

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