最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

原理解析 | JavaScript 計算0.1 + 0.2真的很難,看完才知道!

2020-07-15 14:59 作者:懂點君  | 我要投稿

已經(jīng)很久沒有寫技術(shù)文章了,腦袋瓜有點生銹,寫的不好別見怪,今天就是想帶點干貨給大家分享一下。文章的內(nèi)容有一點點難度,不過基本都是計算機(jī)組成原理的知識,算是溫故而知新吧!

學(xué)過JavaScript的童鞋應(yīng)該非常清楚,0.1 + 0.2 是不等于0.3的,而是等于0.30000000000000004,至于為什么會這樣?好像有點說不清楚,只知道是JavaScript精確度問題,其他不得而知了。沒關(guān)系,看完慢慢就懂了!

目錄

  • 浮點數(shù)十進(jìn)制轉(zhuǎn)二進(jìn)制

  • IEEE 754 標(biāo)準(zhǔn)

  • 浮點數(shù)二進(jìn)制運(yùn)算

  • 實踐擴(kuò)展

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

0.1的二進(jìn)制:0.000110011......0011......(0011無限循環(huán))

0.2的二進(jìn)制:0.00110011......0011...... (0011無限循環(huán))

說明:轉(zhuǎn)換過程就不在這邊描述了

IEEE 754 標(biāo)準(zhǔn)

IEEE二進(jìn)制浮點數(shù)算術(shù)標(biāo)準(zhǔn)(IEEE 754)是20世紀(jì)80年代以來最廣泛使用的浮點數(shù)運(yùn)算標(biāo)準(zhǔn),為許多CPU與浮點運(yùn)算器所采用。
這個標(biāo)準(zhǔn)定義了表示浮點數(shù)的格式(包括負(fù)零-0)與反常值(denormal number)),一些特殊數(shù)值(無窮(Inf)與非數(shù)值(NaN)),以及這些數(shù)值的“浮點數(shù)運(yùn)算符”;它也指明了四種數(shù)值舍入規(guī)則和五種例外狀況(包括例外發(fā)生的時機(jī)與處理方式)。百度百科

浮點數(shù)存儲格式

上圖是64位的雙精度浮點數(shù),最高位是符號位S(sign),中間的11位是指數(shù)E(exponent),剩下的52位為尾數(shù)(有效數(shù)字)M(mantissa)。

浮點數(shù)科學(xué)計數(shù)法

根據(jù)IEEE 754標(biāo)準(zhǔn),任意一個浮點數(shù)的二進(jìn)制都可以用如下公式進(jìn)行表示:

S為符號位:表示浮點數(shù)的正負(fù)(0代表正數(shù),1代表負(fù)數(shù));

E為指數(shù)位:存儲指數(shù),該數(shù)都會加上一個常數(shù)(偏移量),用來表示次方數(shù);

M為尾數(shù)位:表示有效位(尾數(shù)),超出的部分自動進(jìn)1舍0;

雙精度的浮點數(shù)真值(帶有正負(fù)號的數(shù)值是真值)最終可以表示為:


說明:E是無符號整數(shù),長度是11位,取值范圍是為0~2047。因為科學(xué)計數(shù)法中的指數(shù)是可以為負(fù)數(shù),所以約定減去一個中間數(shù)(偏移量)1023,[0,1022] 表示為負(fù),[1024,2047] 表示為正。

浮點數(shù)二進(jìn)制運(yùn)算

規(guī)格化

大部分二進(jìn)制浮點數(shù)都以規(guī)格化格式進(jìn)行存放,以便將有效數(shù)字的精度最大化,提升精確度。

0.1的二進(jìn)制

0.000110011001100110011001100110011001100110011001100110011...... (0011無限循環(huán))

0.1科學(xué)計數(shù)法表示

小數(shù)點向右移動4位,讓其小數(shù)點左邊只有一個“1”。

1.10011001100110011001100110011001100110011001100110011......(0011無限循環(huán)) * 2^-4

根據(jù)IEEE754標(biāo)準(zhǔn),雙精度浮點的尾數(shù)只能存儲52位,加粗的“1”是第53位,根據(jù)進(jìn)1舍0的原則進(jìn)行操作,操作后的值為:

1.1001100110011001100110011001100110011001100110011010* 2^-4

0.1二進(jìn)制存儲格式

指數(shù)-4等于1019(E) – 1023(常量),由此可得E等于1019,把1019轉(zhuǎn)為二進(jìn)制1111111011。

最終表示如下:

0,01111111011;1001100110011001100110011001100110011001100110011010

說明:第一部分為符號位;第二部分為指數(shù)位;第三部分為尾數(shù)位;

0.2的二進(jìn)制

0.001100110011001100110011001100110011001100110011001100110011...... (0011無限循環(huán))

0.2科學(xué)計數(shù)法表示

小數(shù)點向右移動3位,讓其小數(shù)點左邊只有一個“1”。

1.10011001100110011001100110011001100110011001100110011......(0011無限循環(huán)) * 2^-3

加粗的“1”是第53位,根據(jù)進(jìn)1舍0的原則進(jìn)行操作,操作后的值為:

1.1001100110011001100110011001100110011001100110011010...... (0011無限循環(huán)) * 2^-3

0.2二進(jìn)制存儲格式

指數(shù)-3等于1020(E) – 1023(常量),由此可得E等于1020,把1020轉(zhuǎn)為二進(jìn)制1111111100。

最終表示如下:

0,01111111100;1001100110011001100110011001100110011001100110011010

說明:第一部分為符號位;第二部分為指數(shù)位;第三部分為尾數(shù)位;

對階

對階的目的是使兩數(shù)的小數(shù)點位置對齊,方便兩數(shù)進(jìn)行運(yùn)算,換句話說就是兩數(shù)的階碼要相等。根據(jù)小階向大階看齊的原則,應(yīng)使0.1的尾數(shù)向右移動1位(可以理解為小數(shù)點向左移動1位),階碼加1。

尾數(shù)向右移動1位后,階碼和尾數(shù)的值變化如下:

階碼:01111111011 + 1 ——> 01111111100

尾數(shù):

11001100110011001100110011001100110011001100110011010

——> 1100110011001100110011001100110011001100110011001101

加粗的“1”是右移補(bǔ)的位,加粗的0是舍去的位,根據(jù)IEEE 754標(biāo)準(zhǔn)雙精度浮點的尾數(shù)只能存儲52位,遵循進(jìn)1舍0的原則進(jìn)行操作。

0.1的科學(xué)計數(shù)法表示:

0.1100110011001100110011001100110011001100110011001101 *2^-3

0.1的二進(jìn)制存儲格式:

0,01111111100;1100110011001100110011001100110011001100110011001101

尾數(shù)求和

尾數(shù)部分M通常都是規(guī)格化表示的,非"0"的尾數(shù)其第1位總是"1",而這一位也稱作隱藏位,因為存儲的時候該位會被省略。比如存儲1.0110時,只存儲尾數(shù)0110,等到讀取的時候才把第1位的1加補(bǔ)上去,這么做相當(dāng)于多保存了1位有效數(shù)字。

0.1的尾數(shù) + 0.2的尾數(shù) =

0.1100110011001100110011001100110011001100110011001101?+?1.1001100110011001100110011001100110011001100110011010?=?10.0110011001100110011001100110011001100110011001100111

由此可得:

0.1 + 0.2 =?10.0110011001100110011001100110011001100110011001100111* 2^-3

結(jié)果規(guī)格化

根據(jù)尾數(shù)求和的結(jié)果,進(jìn)行規(guī)格化處理,即尾數(shù)向右移1位,階碼加1。

1.00110011001100110011001100110011001100110011001100111?* 2^-2

尾數(shù)只能存儲52位,加粗的“1”需要舍去,根據(jù)進(jìn)1舍0的原則進(jìn)行操作可得:

1.0011001100110011001100110011001100110011001100110100* 2^-2

二進(jìn)制存儲格式:

指數(shù)-2等于1021(E) – 1023(常量),由此可得E等于1021,把1021轉(zhuǎn)為二進(jìn)制01111111101;

0,01111111101;0011001100110011001100110011001100110011001100110100

溢出判斷

浮點數(shù)的溢出其實是階碼的溢出表現(xiàn)出來的,在算術(shù)運(yùn)算過程中要檢查是否產(chǎn)生了溢出。若階碼正常,算術(shù)運(yùn)算正常結(jié)束;若階碼溢出,則要進(jìn)行相應(yīng)處理。

如上求和結(jié)果的階碼為01111111101,沒有產(chǎn)生溢出,因此運(yùn)算結(jié)束。

結(jié)果轉(zhuǎn)為十進(jìn)制

二進(jìn)制存儲格式是計算機(jī)存儲和運(yùn)算的格式,此時把二進(jìn)制轉(zhuǎn)為十進(jìn)制,我們可以看看最終求和的值會是多少?

規(guī)格化的值是轉(zhuǎn)為非規(guī)格化

指數(shù)的值為2,將規(guī)格化的小數(shù)點向左移動2位即可。

1.0011001100110011001100110011001100110011001100110100* 2^-2

——>

0.010011001100110011001100110011001100110011001100110100

非規(guī)格化的值轉(zhuǎn)成十進(jìn)制

0.1 + 0.2 =

0.3000000000000000444089209850062616169452667236328125

此時此刻,你應(yīng)該明白JavaScript中0.1 + 0.2 = 0.30000000000000004 這個值是怎么來的吧。

實踐擴(kuò)展

為了方便大家學(xué)習(xí)與實踐,提供如下PHP實踐代碼,它是將“0.010011001100110011001100110011001100110011001100110100”轉(zhuǎn)成十進(jìn)制的功能代碼,大家可以嘗試測試一下。

var_dump(number_format(0+ 1 * pow(2, -2) + 0 + 0 + 1 * pow(2, -5) + 1 * pow(2, -6) + 0 + 0 + 1 * pow(2,-9) + 1 * pow(2, -10) + 0 + 0 + 1 * pow(2, -13) + 1 * pow(2, -14) + 0 + 0 + 1 *pow(2, -17) + 1 * pow(2, -18) + 0 + 0 + 1 * pow(2, -21) + 1 * pow(2, -22) + 0 +0 + 1 * pow(2, -25) + 1 * pow(2, -26) + 0 + 0 + 1 * pow(2, -29) + 1 * pow(2,-30) + 0 + 0 + 1 * pow(2, -33) + 1 * pow(2, -34) + 0 + 0 + 1 * pow(2, -37) + 1* pow(2, -38) + 0 + 0 + 1 * pow(2, -41) + 1 * pow(2, -42) + 0 + 0 + 1 * pow(2,-45) + 1 * pow(2, -46) + 0 + 0 + 1 * pow(2, -49) + 1 * pow(2, -50) + 0 + 1 *pow(2, -52) + 0 + 0, 52));

好了,干貨分享完畢,謝謝大家!


原理解析 | JavaScript 計算0.1 + 0.2真的很難,看完才知道!的評論 (共 條)

分享到微博請遵守國家法律
宁都县| 金阳县| 通辽市| 合川市| 宜都市| 兖州市| 马鞍山市| 乌兰浩特市| 广宁县| 洪湖市| 阜南县| 保定市| 区。| 宜州市| 长泰县| 中西区| 麻城市| 阳曲县| 夹江县| 曲沃县| 沐川县| 甘肃省| 浦江县| 绵竹市| 大安市| 纳雍县| 抚顺县| 鄂州市| 清原| 平和县| 宣汉县| 昔阳县| 乐陵市| 漳平市| 巴青县| 车险| 枞阳县| 正阳县| 县级市| 五大连池市| 武穴市|