浮點數在內存中的存儲結構

浮點數在內存中的存儲可以參考《IEEE754標準》https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF

參考博文:IEEE754詳解(最詳細簡單有趣味的介紹)-CSDN博客



單精度float占內存4字節,最高位bit31表示符號位,指數位bit23~bit30占用8個bit位,剩余的23個bit表示尾數。

雙精度double占用內存8字節,最高位bit63表示符號位,指數位bit52~bit62占用11個bit位,剩余的52個bit表示尾數。

字節長度符號位S指數位E尾數M
單精度4字節1 [31]8?[30-23]23?[22-0]
雙精度8字節1 [63]11?[62-52]52?[51-0]



任何一個數,都可以使用不同的權重表示,最終的計算結果公式如下:

假如有一個數:AnAn-1An-2...A2A1B1B2...Bn-1Bn,其中A1~An表示整數部分的每一位數,B1~Bn表示小數部分的每一位數。權重為Q,則

S = An*Q^(n-1)+An-1*Q^(n-2)+...+A2*Q^1+A1*Q^0+B1*Q^(-1)+B2*Q^(-2)+...Bn-1*Q^(-(n-1))+Bn*Q^(-n)

例如十進制數:123.456,對應的十進制數是

S = 1*10^2+2*10^1+3*10^0+4*10^(-1)+5*10^(-2)+6*10^(-3)

再比如二進制數:1011.011,對應的十進制數是

S = 1*2^3+0*2^2+1*2^1+1*2^0+0*2^(-1)+1*2^(-2)+1*2^(-3) = 11.365

再比如八進制數:56.76,對應的十進制是

S = 5*8^1+6*8^0+7*8^(-1)+6*8^(-2) = 46.96875

將10進制數轉為其他進制,比如將整數為A,小數為B變為b進制(123.456:整數A=123,小數B=0.456),則步驟如下:

整數部分:

1. A除以b得到商B和余數R1

2. B除以b得到商C和余數R2

3. .................................Rn-1

4. 重復2,直到商為0,余數為Rn

則整數部分是:RnRn-1...R2R1

小數部分:

1. 小數B乘以b得到積B',再將B'拆分成整數部分F1和小數C

2. 小數C乘以b得到積C',再將C'拆分成整數部分F2和小數D

3. 小數D乘以b得到積D',再將D'拆分成整數部分F3和小數E

4. 重復上述過程,直到小數為0。(有可能永遠不會等于0)

則小數部分是:F1F2F3...Fn-1Fn..........

所以最終10進制轉為其他進制的結果就是:RnRn-1...R2R1.F1F2F3...Fn-1Fn.........

注意R1和F1之間有一個小數點。



有了上面的基礎認知后,我們來看看浮點數是如何存儲在內存中的

先說單精度

指數是8位bit,所以可以表示為0~255,但是指數存在正數和負數,所以IEEE754規定,存入內存時E的真實值必須再加上一個中間數127(2^7-1)

再說雙精度

指數是11位bit,所以可以表示為0~2047,但是指數存在正數和負數,所以IEEE754規定,存入內存時E的真實值必須再加上一個中間數1023(2^11-1)

例:2^10的E是10,所以保存為32位浮點數的時候,E必須保存為10+127=137,即10001001

保存為64位浮點數的時候,E保存為10+1023=1033,即10000001001



根據《IEEE754標準》規定,浮點數在計算機中是以科學計數表示方法存儲的,例如123.456表示為1.23456*10^2

下面使用例子來說明存儲浮點數(正數和負數計算方式一樣,唯一區別就是最高bit位不同而已)

十進制數:123.456

按照公式,它的二進制是:1111011.0111010010111100011010100111111011111001110110.....后面省略不計算

它的科學表示方式是1.1110110111010010111100011010100111111011111001110110.....*2^6所以如下(以單精度為例):

符號位:S=0

指數位:E=6+127=133,二進制是?10000101

尾數:M=1.1110110111010010111100011010100111111011111001110110......按照科學計數表示法來規定,小數點前面一定是1,所以IEEE754為了節省1一個bit,默認將小數點前面的1省略掉,所以實際M=1110110111010010111100011010100111111011111001110110......,右因為單精度的M只占23位,所以M=11101101110100101111001(第24位是1,需要進一位,遵循逢二進一原則)

所以最終的123.456在內存中的二進制是:

0?10000101?11101101110100101111001=0x42F6E979

十進制數:0.0456

二進制為:0.000010111010110001110001000011001011001010010101111010011110000...

科學表示:1.0111010110001110001000011001011001010010101111010011110000...*2^(-5)所以如下(單精度):

符號位:S=0

指數位:E=-5+127=122,二進制是?01111010

尾數:M=01110101100011100010001

所以最終的0.0456在內存中的二進制是:

0?01111010?01110101100011100010001=0x3D3AC711



十進制浮點數轉為二進制存儲的計算步驟:

1. 確定符號位,正數S=0,負數S=1

2. 將正數轉為二進制表示,例如123.456=1111011.0111010010111100011010100111111011111001110110.....

0.0456=0.000010111010110001110001000011001011001010010101111010011110000...

3. 將小數點進行左移/右移e位,使得小數點前面有且僅有一個有意義的數字1,即:變為科學計數表達形式。(左移得到的指數是正數,右移得到的是負數)

123.456的二進制小數點需要左移6位

0.0456的二進制小數點需要右移5位

4. 指數加上中間數base(單精度base=127,雙精度base=1023)

? ? E = e+base

? ?123.456的E=6+127=133? ? ? ? ? ? ? ? ?0.0456的E=-5+127=122

5. 將科學計數法表示的二進制數,從小數點后面第一位開始(因為小數點前面肯定是1,為了節省1bit,所以去掉),從左到右依次填充到尾數位最后一位遵循逢二進一原則,從而得到M

6. 將S? E? ?M分別填充到對應的位,即可得到二進制存儲。



內存中關于二進制轉為浮點數

根據國際標準 IEEE754,任意一個浮點數都可以用如下形式來表示:

V = (-1)^S * M * 2^E。
符號 S 決定浮點數的是負數(S=1)還是正數(S=0),由一位符號位表示。
有效數M是一個二進制小數,它的范圍在1~2之間。
指數E是2的冪,可正可負,作用是對浮點數加權,由8位或11位的指數域表示。

浮點數的二進制解析有以下解碼格式
指數域E尾數域M說明
格式化值------

符合一般公式

此時的 E = E-base

非格式化值全是1全是0表示無窮
全是1不全是0表示NaN(不是一個有效數字)
特殊值全是0不全是0

此時的E=1-base。

M不再加上第一位的1,而是還原為0.xxxxxx的小數

0全是0全是0固定值0
--將整數轉為浮點數float
local function Hex2Float(iValue)--[[--以下計算方法參考: https://docs.oracle.com/javase/6/docs/api/java/lang/Float.html#floatToIntBits(float)iValue = iValue&0xFFFFFFFFif 0x7f800000==iValue then --正無窮大return math.hugeelseif 0xff800000==iValue then --負無窮大return -math.hugeelseif (0x7f800001<=iValue and iValue<=0x7fffffff) or (0xff800001<=iValue and iValue<=0xffffffff) then --不是一個有效的數字return nilend--是一個有效的數字local bits = iValuelocal sif (bits>>31)&0x1==0 then s = 1else s = -1endlocal e = (bits>>23) & 0xfflocal mif 0==e then m = (bits & 0x7fffff) << 1else m = (bits & 0x7fffff) | 0x800000endreturn s*m*(2^(e-150)) -- s * m/(2^23) * 2^(e-127) 中間一部分相當于是十進制里面的 123/100=1.23一個操作]]----[[--詳細解釋實現原理--s e m分別占位: 1 8 23iValue = iValue&0xFFFFFFFFlocal s = (iValue>>31)&0x01local e = (iValue>>23)&0xFFlocal m = iValue&0x7FFFFFlocal S = slocal E = e-127local M = 1if e==0 and m==0 then --指數和尾數都是0的,表示0return 0.0 elseif e==0xFF and m==0 then --指數全是1,而尾數都是0的,表示無窮if s==1 thenreturn -math.hugeelsereturn math.hugeendelseif e==0xFF and m~=0 then --指數全是1,而尾數不全是0的,表示NaN(不是一個數)return nilelseif e==0 and m~=0 then --指數全是0,而尾數不全是0的,表示一種非規格化的數字E=-126 -- 1-127M = 0endfor i=1,23 doif (m>>(23-i))&0x01==0x01 thenM = M+2^(-i)endend-- f = (-1)^s * m * 2^ereturn ((-1)^S) * M * (2^E)]]--local binary = {}for i=3,0,-1 dotable.insert(binary,(iValue>>(i*8))&0xFF)endlocal v,pos = string.unpack(">f", string.char(table.unpack(binary)))return v
end

--將整數轉為浮點數double
local function Hex2Double(iValue)--[[--以下計算方法參考: https://docs.oracle.com/javase/6/docs/api/java/lang/Double.html#doubleToLongBits(double)iValue = iValue&0xFFFFFFFFFFFFFFFFif 0x7ff0000000000000==iValue then --正無窮大return math.hugeelseif 0xfff0000000000000==iValue then --負無窮大return -math.hugeelseif (0x7ff0000000000001<=iValue and iValue<=0x7fffffffffffffff) or (0xfff0000000000001<=iValue and iValue<=0xffffffffffffffff) then --不是一個有效的數字return nilend--是一個有效的數字local bits = iValuelocal sif (bits>>63)&0x1==0 then s = 1else s = -1endlocal e = (bits>>52) & 0x7fflocal mif 0==e then m = (bits & 0xfffffffffffff) << 1else m = (bits & 0xfffffffffffff) | 0x10000000000000endreturn s*m*(2^(e-1075))]]----[[--詳細解釋實現原理--s e m分別占位: 1 11 52iValue = iValue&0xFFFFFFFFFFFFFFFFlocal s = (iValue>>63)&0x01local e = (iValue>>52)&0x7FFlocal m = iValue&0xFFFFFFFFFFFFFlocal S = slocal E = e-1023local M = 1if e==0 and m==0 then --指數和尾數都是0的,表示0return 0.0 elseif e==0x7FF and m==0 then --指數全是1,而尾數都是0的,表示無窮if s==1 thenreturn -math.hugeelsereturn math.hugeendelseif e==0x7FF and m~=0 then --指數全是1,而尾數不全是0的,表示NaN(不是一個數)return nilelseif e==0 and m~=0 then --一種非規格化的數字E=-1022 -- 1-1023M = 0endfor i=1,52 doif (m>>(52-i))&0x01==0x01 thenM = M+2^(-i)endend-- f = (-1)^s * m * 2^ereturn ((-1)^S) * M * (2^E)]]--local binary = {}for i=7,0,-1 dotable.insert(binary,(iValue>>(i*8))&0xFF)endlocal v,pos = string.unpack(">d", string.char(table.unpack(binary)))return v
end

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/39661.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/39661.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/39661.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

國家海岸線變化評估:新英格蘭和中大西洋沿岸海岸線的歷史變化

National Assessment of Shoreline Change: Historical Shoreline Change along the New England and Mid-Atlantic Coasts 國家海岸線變化評估&#xff1a;新英格蘭和中大西洋沿岸海岸線的歷史變化 摘要 海灘侵蝕是美國許多公海沿岸的一個長期問題。隨著沿岸人口的不斷增加…

永輝超市購物卡有什么用?

感覺現在在超市買東西&#xff0c;還不如網購 這不&#xff0c;端午的時候&#xff0c;朋友送的永輝卡&#xff0c;一直沒時間去用&#xff0c;我總擔心過期 但是去了超市后&#xff0c;又不知道買什么&#xff0c;最后空手而歸 還好收卡云可以回收永輝卡&#xff0c;兩張三…

《C++20設計模式》適配器模式經驗分享

文章目錄 一、前言二、對于接口的討論三、實現1、對象適配器1.1 UML類圖1.2 實現 2、類適配器 四、最后 一、前言 從適配器模式開始就是類的組合聚合&#xff0c;類與類之間結構性的問題了。 適配器模式解決的問題&#xff1a; 適配器模式能夠在不破壞現有系統結構的情況下&a…

mapreduce實現bean的序列化與反序列化

目錄 序列化&#xff08;Serialization&#xff09; 反序列化&#xff08;Deserialization&#xff09; 事例操作 UserSale 重寫序列化方法 重寫反序列化 重寫toString方法 SaleMapper SaleReducer SaleDriver 序列化&#xff08;Serialization&#xff09; 序列化是將…

【后端面試題】【中間件】【NoSQL】MongoDB的配置服務器、復制機制、寫入語義和面試準備

MongoDB的配置服務器 引入了分片機制之后&#xff0c;MongoDB啟用了配置服務器(config server) 來存儲元數據&#xff0c;這些元數據包括分片信息、權限控制信息&#xff0c;用來控制分布式鎖。其中分片信息還會被負責執行查詢mongos使用。 MongoDB的配置服務器有一個很大的優…

WPF----自定義滾動條ScrollViewer

滾動條是項目當中經常用到的一個控件&#xff0c;大部分對外項目都有外觀的需求&#xff0c;因此需要自定義&#xff0c;文中主要是針對一段動態的狀態數據進行展示&#xff0c;并保證數據始終在最新一條&#xff0c;就是需要滾動條滾動到底部。 1&#xff0c;xaml中引入 <…

zxing-cpp+OpenCV根據字符串生成條形碼

編譯構建 需要使用到 CMake、Git、GCC 或 MSVC。 github 鏈接&#xff1a;https://github.com/zxing-cpp/zxing-cpp 編譯之前請確保&#xff1a; 確保安裝了 CMake 版本 3.15 或更高版本。 確保安裝了與 C17 兼容的編譯器(最低VS 2019 16.8 / gcc 7 / clang 5)。 編譯構建…

Python面試寶典第4題:環形鏈表

題目 給你一個鏈表的頭節點 head &#xff0c;判斷鏈表中是否有環。如果存在環 &#xff0c;則返回 true 。 否則&#xff0c;返回 false 。 如果鏈表中有某個節點&#xff0c;可以通過連續跟蹤 next 指針再次到達&#xff0c;則鏈表中存在環。 為了表示給定鏈表中的環&#xf…

重寫父類方法、創建單例對象 題目

題目 JAVA27 重寫父類方法分析&#xff1a;代碼&#xff1a; JAVA28 創建單例對象分析&#xff1a;代碼&#xff1a; JAVA27 重寫父類方法 描述 父類Base中定義了若干get方法&#xff0c;以及一個sum方法&#xff0c;sum方法是對一組數字的求和。請在子類 Sub 中重寫 getX() 方…

AI智能體|AI打工我躺平!使用扣子Coze智能體自動生成和發布文章到微信公眾號(一)

大家好&#xff0c;我是無界生長&#xff0c;國內最大AI付費社群“AI破局俱樂部”初創合伙人。這是我的第 44 篇原創文章——《AI智能體&#xff5c;AI打工我躺平&#xff01;使用扣子Coze智能體自動生成和發布文章到微信公眾號&#xff08;一&#xff09;》 AI智能體&#xf…

《涅朵奇卡:一個女人的一生》讀后感

這周的計劃是看完海明威的《喪鐘為誰而鳴》&#xff0c;但是因為下班晚&#xff0c;而且書的體量大&#xff0c;所以只看了一半。本來以為這周的閱讀計劃完不成了&#xff0c;不料昨天加完班后拿起新到的《涅朵奇卡&#xff1a;一個女人的一生》&#xff0c;不自覺就陷進去了&a…

端口聚合基礎知識

一、什么是端口聚合 端口聚合是將多個物理端口捆綁在一起&#xff0c;形成一個邏輯鏈路&#xff0c;以實現帶寬增加、提高冗余和負載均衡的技術。端口聚合&#xff0c;也稱為以太通道&#xff08;Ethernet Channel&#xff09;&#xff0c;主要用于交換機之間的連接。在具有多…

開發數字藥店APP實戰:互聯網醫院系統源碼詳解

本篇文章&#xff0c;筆者將深入探討如何開發一個功能完善的數字藥店APP&#xff0c;并詳細解析互聯網醫院系統的源碼實現。 一、數字藥店APP的需求分析 應具備以下基本功能&#xff1a; 用戶注冊與登錄 藥品搜索與瀏覽 在線下單與支付 訂單管理 健康咨詢與遠程醫療 個人…

partition()方法——分割字符串為元組

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 語法參考 partition()方法根據指定的分隔符將字符串進行分割。如果字符串中包含指定的分隔符&#xff0c;則返回一個3元的元組&#xff0c;第一個為…

Perl 語言開發(四):條件語句

目錄 1. 概述 2. if 語句 3. else 語句 4. elsif 語句 5. unless 語句 6. 嵌套條件語句 7. 三元運算符 8. 智能匹配運算符 9. given-when 語句 10. 條件修飾符 11. 高級條件語句應用 11.1 數據驗證 11.2 配置文件解析 11.3 異常處理 12. 條件語句的最佳實踐 12…

Spring Boot+Mybatis Plus 使用Redis實現二級緩存具體步驟以及代碼

下面是使用Spring BootMybatis Plus和Redis實現二級緩存的具體步驟和代碼示例&#xff1a; 1. 首先&#xff0c;確保你已經添加了Spring Boot、Mybatis Plus和Redis的依賴。 2. 在Spring Boot的配置文件中添加Redis的配置&#xff0c;如下所示&#xff1a; yaml spring: r…

wordpress:更新網站域名后后頁面無法訪問,頁面媒體文件異常(已解決)

WordPress 在數據庫中存儲了許多配置信息,包括網站的域名。如果更新了域名,但數據庫中的舊域名沒有更新,WordPress 將無法正確生成頁面鏈接或重定向訪問請求。 一、更新域名 在wp-config.php 文件中,添加或更新你的新域名! define(WP_HOME, http://172.18.214.195:32520…

Linux_fileio學習

參考韋東山老師教程&#xff1a;https://www.bilibili.com/video/BV1kk4y117Tu?p12 目錄 1. 文件IO函數分類2. 函數原型2.1 系統調用接口2.2 標準IO接口 3. fileio內部機制3.1 系統調用接口內部流程3.1 dup函數使用3.2 dup2函數使用 4. open file4.1 open實例4.2 open函數分析…

Cocos如何跟Android通信?

點擊上方億元程序員+關注和★星標 引言 Cocos如何跟Android通信 大家好,相信小伙伴們通過閱讀筆者前幾期的文章**《Cocos打安卓包打不出來?看看這個》,對Cocos**如何打安卓包有了一定的了解。 但是,除了把安卓包打出來,另外還有一個重要的就是要能夠調用安卓提供的Java方…

華為HCIP Datacom H12-821 卷21

1.單選題 以下關于PIM-SM中SPT切換的描述,錯誤的是哪一項? A、若所有組播流量都經過RP路由器,則RP路由器可能成為數據轉發的瓶頸 B、SPT路徑最短,轉發性能更優 C、SPT 切換完成后,組播流量依然經過 ReT 樹 D、RPT 樹可能不是組播流量轉發的最優路徑 正確答案: C 解析…