0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

談一談浮點(diǎn)數(shù)的精度問題

冬至配餃子 ? 來源:最后一個bug ? 作者:bug菌 ? 2022-08-11 14:28 ? 次閱讀

最近進(jìn)行代碼的review過程中看到同事在代碼中直接拿浮點(diǎn)數(shù)相等來作為條件,其他同事提醒他的時候,他還迷迷糊糊不知道為什么,所以就有了今天這篇文章。

1、浮點(diǎn)數(shù)據(jù)的不均勻

我們經(jīng)常會談到浮點(diǎn)數(shù)的精度問題,float-單精度,double-雙精度,double類型相比float類型精度更高,相應(yīng)的需要的內(nèi)存字節(jié)個數(shù)也越多,談到精度的問題,其實(shí)也就說明這種數(shù)據(jù)類型并不能夠連續(xù)的標(biāo)識任何的點(diǎn),整形數(shù)就不用說了,小數(shù)部分直接不能標(biāo)識。

毒王這篇文章基本上可以從浮點(diǎn)數(shù)的存儲到表意來較好的認(rèn)識浮點(diǎn)數(shù)數(shù)據(jù)類型,但是中間部分對于浮點(diǎn)數(shù)精度部分的介紹并不是很形象,所以今天再詳細(xì)一點(diǎn)說明一下。

首先我們要認(rèn)識到通常float類型的變量占據(jù)四個字節(jié),而uint32_t的整形類型也是占據(jù)四個字節(jié),既然都是四個字節(jié),那他們所能表示的不同數(shù)據(jù)個數(shù)是一樣的。

如果不太理解,可以把float看成4個bit,uint32_t也是4個bit,那么他們不管經(jīng)過什么變換,每個數(shù)據(jù)類型都只能夠標(biāo)識16個數(shù)。

好,如下圖以4字節(jié)float的數(shù)據(jù)存儲模型所示:

poYBAGL0oKOAGnTXAABXAQp6GqM658.pngpoYBAGL0oK-AFdFKAACbC03w1Nw937.png

4個字節(jié)的浮點(diǎn)數(shù),不像無符號整形所有的bit都是數(shù)據(jù)區(qū),并且以每個數(shù)據(jù)之間相差1均勻分布,而浮點(diǎn)數(shù)把這4個字節(jié)分為了不同的區(qū)來起到不同的作用,從而用另外一種方式表達(dá)數(shù)據(jù)。

其指數(shù)部分越大,表示的數(shù)據(jù)就越大,但是尾數(shù)部分只能表示到23位,這樣的話導(dǎo)致數(shù)據(jù)的精度就越差,如果不太理解可以用一個較大的數(shù)通過上面的轉(zhuǎn)換方式進(jìn)行換算,便能理解。

poYBAGL0oMOAQIDRAABoH8OBdKY496.png

所以同樣是4個字節(jié),根據(jù)浮點(diǎn)數(shù)的表示,越接近0就越稠密,越遠(yuǎn)離0就越稀疏,呈現(xiàn)一種不均勻的數(shù)據(jù)排列狀態(tài),如上圖所示,同樣它也也不能標(biāo)識實(shí)軸上任意的點(diǎn)。

2、驗(yàn)證一下不均勻

好了,講了這么多理論,多多少少得來點(diǎn)程序驗(yàn)證一下:

pYYBAGL0oNWAHNSBAAEPNVlIAkk408.png

看看上面的代碼,這還用說,肯定這兩個數(shù)相等呀,相減也等于0,然而看一下輸出結(jié)果:

poYBAGL0oOyAdQmtAABx3Fdix3k093.png

結(jié)果并不相等,并且相差還不少。

其結(jié)果也就說明了浮點(diǎn)數(shù)在大數(shù)的標(biāo)識精度不好,只能近似標(biāo)識,同時也說明了為什么一般不使用浮點(diǎn)數(shù)相等來進(jìn)行判斷的原因。

這也是為什么有時候明明我們采用直接編碼用準(zhǔn)確的浮點(diǎn)數(shù),到了浮點(diǎn)數(shù)變量里面卻損失了精度,因?yàn)?個字節(jié)的float標(biāo)識不了,只能近似處理。

3、非要判斷相等

由于有些應(yīng)用非要使用浮點(diǎn)數(shù)進(jìn)行相等的處理,我們不應(yīng)該直接使用浮點(diǎn)數(shù)進(jìn)行等于號的判斷,而是要在一定的誤差和精度范圍內(nèi)進(jìn)行滿足。

poYBAGL0oPuAFqUrAACMOZYGM8M317.png

如上圖所示代碼是比較常用的處理辦法,在往期的文章中,bug菌沒有詳細(xì)的講解這個誤差宏的定義,前面了解到當(dāng)數(shù)據(jù)比較大的時候相鄰的差值會比較大,這樣就存在兩個浮點(diǎn)數(shù)的差值大于所設(shè)置的誤差范圍而無法判斷相等。

所以這樣的處理辦法來判斷浮點(diǎn)數(shù)近似相等會存在一些局限性。

那有沒有相對更好一點(diǎn)的辦法呢?

當(dāng)然是有的,不然接下來沒得寫了。

還是要從浮點(diǎn)數(shù)的存儲和標(biāo)識出發(fā)來處理該問題,既然浮點(diǎn)數(shù)天然就存在一定的誤差,而有時候計(jì)算又無法獲得唯一的數(shù)值,如下圖所示,浮點(diǎn)數(shù)計(jì)算出來的實(shí)軸上的值都會因?yàn)楦↑c(diǎn)數(shù)無法存儲標(biāo)識而近似到其相鄰的可以標(biāo)識的數(shù)值上。

poYBAGL0oRGAYTzNAAB2XzdRbF0271.png

從浮點(diǎn)的存儲模型來看,指數(shù)部分代表著浮點(diǎn)數(shù)的范圍,尾數(shù)部分代表著浮點(diǎn)數(shù)的精度,那么尾數(shù)的最后一位其實(shí)就表示了浮點(diǎn)數(shù)的當(dāng)前數(shù)值附近的精度。

于是對浮點(diǎn)的近似相等進(jìn)行了算法上的修改,如下代碼所示:

poYBAGL0oSKAZZujAACMlPdwF2U141.png

解釋一下 :

如果直接相等,說明浮點(diǎn)數(shù)各數(shù)據(jù)位都相等;而如果不相等可能相鄰,于是強(qiáng)制轉(zhuǎn)化為整形,比較尾數(shù)最后一位是否不同。

這里使用一個小技巧,采用異或的處理辦法,如果其他位都相同,而最后一位不同,結(jié)果就等于1,認(rèn)為兩個浮點(diǎn)數(shù)近似相等。

本文到此結(jié)束,我相信大家應(yīng)該對浮點(diǎn)數(shù)有了一個更加深入的了解,面對一些問題心中也會有一些答案,比如浮點(diǎn)數(shù)為什么不能作為switch的參數(shù),也是同樣的原因。

但總的來說還是建議大家不要判斷浮點(diǎn)數(shù)相等,非要用也要特別小心。


審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Switch
    +關(guān)注

    關(guān)注

    1

    文章

    532

    瀏覽量

    58109
  • 數(shù)據(jù)存儲
    +關(guān)注

    關(guān)注

    5

    文章

    959

    瀏覽量

    50834
  • 浮點(diǎn)數(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    59

    瀏覽量

    15856
收藏 人收藏

    評論

    相關(guān)推薦

    請問如何打印浮點(diǎn)數(shù)或雙精度變量?

    如何打印浮點(diǎn)數(shù)或雙精度變量?
    發(fā)表于 07-12 08:24

    官方例程modbus slave rtu,浮點(diǎn)數(shù)精度不對是怎么回事?

    官方例程 modbus slave rtu, 浮點(diǎn)數(shù)精度不對,對保持寄存器設(shè)置浮點(diǎn)數(shù),讀取到的浮點(diǎn)數(shù)結(jié)果
    發(fā)表于 07-19 08:10

    浮點(diǎn)數(shù)如何存儲?

    浮點(diǎn)數(shù)如何存儲玩轉(zhuǎn)浮點(diǎn)數(shù)
    發(fā)表于 12-30 07:10

    MCU中雙精度浮點(diǎn)數(shù)是用什么格式存儲的?

    MCU中雙精度浮點(diǎn)數(shù)是用什么格式存儲的
    發(fā)表于 10-11 06:24

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

    浮點(diǎn)數(shù)的表示方法  浮點(diǎn)數(shù),是指小數(shù)點(diǎn)在數(shù)據(jù)中的位置可以左右移動的數(shù)據(jù)。它通常被表示成:    N = M* RE  這里的M(Mantissa)被稱為浮點(diǎn)數(shù)
    發(fā)表于 10-13 17:13 ?1.6w次閱讀
    <b class='flag-5'>浮點(diǎn)數(shù)</b>的表示方法

    浮點(diǎn)數(shù)常用的編碼方法

    浮點(diǎn)數(shù)常用的編碼方法  前面已經(jīng)說到,在計(jì)算機(jī)內(nèi),浮點(diǎn)數(shù)被表示為如下格式:    通常情況
    發(fā)表于 10-13 17:21 ?4431次閱讀
    <b class='flag-5'>浮點(diǎn)數(shù)</b>常用的編碼方法

    modbus 如何讀取浮點(diǎn)數(shù)

    本文為大家介紹modbus讀取浮點(diǎn)數(shù)的兩個程序設(shè)計(jì)。
    發(fā)表于 02-08 10:03 ?1.4w次閱讀

    Xilinx怎么定點(diǎn)數(shù)轉(zhuǎn)浮點(diǎn)數(shù)

    轉(zhuǎn)化為的浮點(diǎn)數(shù)可以是單精度也可以是雙精度。
    發(fā)表于 07-05 08:09 ?3859次閱讀
    Xilinx怎么定<b class='flag-5'>點(diǎn)數(shù)</b>轉(zhuǎn)<b class='flag-5'>浮點(diǎn)數(shù)</b>

    什么是浮點(diǎn)數(shù)?浮點(diǎn)數(shù)在內(nèi)存中的存儲

    浮點(diǎn)型簡單講就是實(shí)數(shù)的意思。浮點(diǎn)數(shù)在計(jì)算機(jī)中用以近似表示任意某個實(shí)數(shù)。
    的頭像 發(fā)表于 11-09 11:07 ?5113次閱讀
    什么是<b class='flag-5'>浮點(diǎn)數(shù)</b>?<b class='flag-5'>浮點(diǎn)數(shù)</b>在內(nèi)存中的存儲

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

    Python數(shù)據(jù)類型第種:字符串(str)。 Python數(shù)據(jù)類型第二種:整數(shù)(int)。 Python數(shù)據(jù)類型第三種:浮點(diǎn)數(shù),浮點(diǎn)數(shù)的英文名是float,浮點(diǎn)數(shù)沒有簡寫。
    的頭像 發(fā)表于 02-23 14:58 ?4461次閱讀

    點(diǎn)數(shù)浮點(diǎn)數(shù)的概念 浮點(diǎn)數(shù)二進(jìn)制序列與指數(shù)表達(dá)式之間的轉(zhuǎn)化

    的缺點(diǎn):由于小數(shù)點(diǎn)位置固定不變,定點(diǎn)數(shù)所表示的數(shù)的范圍非常有限,不能同時表達(dá)特別大或特別小的數(shù),所以才出現(xiàn)了浮點(diǎn)數(shù),以此來擴(kuò)充數(shù)的范圍,同時浮點(diǎn)數(shù)也廣泛應(yīng)用于精度要求高的場合。簡單的理
    的頭像 發(fā)表于 08-22 16:06 ?7604次閱讀
    定<b class='flag-5'>點(diǎn)數(shù)</b>和<b class='flag-5'>浮點(diǎn)數(shù)</b>的概念 <b class='flag-5'>浮點(diǎn)數(shù)</b>二進(jìn)制序列與指數(shù)表達(dá)式之間的轉(zhuǎn)化

    精度和雙精度浮點(diǎn)數(shù)的區(qū)別

    在計(jì)算機(jī)科學(xué)和數(shù)值計(jì)算中,浮點(diǎn)數(shù)種用于表示實(shí)數(shù)的數(shù)據(jù)類型。浮點(diǎn)數(shù)有兩種精度級別:單精度和雙精度
    的頭像 發(fā)表于 12-13 10:55 ?9911次閱讀

    精度和雙精度浮點(diǎn)數(shù)的區(qū)別

    。 單精度浮點(diǎn)數(shù),也稱為單精度浮點(diǎn)數(shù)格式,用于在計(jì)算機(jī)中表示32位二進(jìn)制格式的浮點(diǎn)數(shù)。個單
    的頭像 發(fā)表于 12-15 10:25 ?5131次閱讀

    modbus浮點(diǎn)數(shù)怎么讀取

    Modbus是種通信協(xié)議,常用于工業(yè)自動化系統(tǒng)中的設(shè)備之間的通信。它支持多種數(shù)據(jù)類型,包括整數(shù)、浮點(diǎn)數(shù)、字符串等。浮點(diǎn)數(shù)在工業(yè)領(lǐng)域中廣泛應(yīng)用,因此了解如何讀取和處理Modbus浮點(diǎn)數(shù)
    的頭像 發(fā)表于 12-28 14:38 ?5675次閱讀

    文帶你秒懂IEEE 754浮點(diǎn)數(shù)

    、簡介1、常見的浮點(diǎn)數(shù)表示方式是IEEE754標(biāo)準(zhǔn),它規(guī)定了浮點(diǎn)數(shù)的存儲格式和運(yùn)算規(guī)則,這個標(biāo)準(zhǔn)定義了兩種浮點(diǎn)數(shù)表示:單精度和雙
    的頭像 發(fā)表于 03-18 08:09 ?7903次閱讀
    <b class='flag-5'>一</b>文帶你秒懂IEEE 754<b class='flag-5'>浮點(diǎn)數(shù)</b>