浮點數

叶际参差發表於2024-06-07

十進位制小數與二進位制數的轉換

  1. 十進位制整數轉換為二進位制整數

十進位制整數轉換為二進位制整數採用"除2取餘,逆序排列"法。具體做法是:用2去除十進位制整數,可以得到一個商和餘數;再用2去除商,又會得到一個商和餘數,如此進行,直到商為零時為止,然後把先得到的餘數作為二進位制數的低位有效位,後得到的餘數作為二進位制數的高位有效位,依次排列起來。

例如把 (173)10 轉換為二進位制數。

解:

  1. 十進位制小數轉換為二進位制小數
    十進位制小數轉換成二進位制小數採用"乘2取整,順序排列"法。具體做法是:用2乘十進位制小數,可以得到積,將積的整數部分取出,再用2乘餘下的小數 部分,又得到一個積,再將積的整數部分取出,如此進行,直到積中的小數部分為零,或者達到所要求的精度為止。

然後把取出的整數部分按順序排列起來,先取的整數作為二進位制小數的高位有效位,後取的整數作為低位有效位。

例如把(0.8125)轉換為二進位制小數。

解:

浮點數在記憶體的儲存格式

32位系統和64位系統都有float和double兩種型別的小數,分別叫做單精度和雙精度,它們在記憶體中的佈局如下:

高位
精度 符號位 階碼 尾數
單精度(float) 31 30-23 22-0
雙精度(double) 63 62-52 51-0

符號位:0表示正,1表示負

階碼:這裡階碼採用移碼錶示,對於float型資料其規定偏置量為127,階碼有正有負,對於8位二進位制,則其表示範圍為-128-127,double型規定為1023,其表示範圍為-1024-1023。比如對於float型資料,若階碼的真實值為2,則加上127後為129,其階碼錶示形式為10000010

尾數:有效數字位,即部分二進位制位(小數點後面的二進位制位),因為規定M的整數部分恆為1,所以這個1就不進行儲存了。

下面舉例說明:

float型資料125.5轉換為標準浮點格式

125二進位制表示形式為1111101,小數部分表示為二進位制為 1,則125.5二進位制表示為1111101.1,由於規定尾數的整數部分恆為1,則表示為1.1111011*2^6,階碼為6,加上127為133,則表示為10000101,而對於尾數將整數部分1去掉,為1111011,在其後面補0使其位數達到23位,則為11110110000000000000000

則其二進位制表示形式為

0 10000101 11110110000000000000000,則在記憶體中存放方式為:

00000000   低地址
00000000
11111011
01000010   高地址

而反過來若要根據二進位制形式求算浮點數如0 10000101 11110110000000000000000

由於符號為為0,則為正數。階碼為133-127=6,尾數為11110110000000000000000,則其真實尾數為1.1111011。所以其大小為

1.1111011*26,將小數點右移6位,得到1111101.1,而1111101的十進位制為125,0.1的十進位制為1*2(-1)=0.5,所以其大小為125.5。

同理若將float型資料0.5轉換為二進位制形式

0.5的二進位制形式為0.1,由於規定正數部分必須為1,將小數點右移1位,則為1.0*2^(-1),其階碼為-1+127=126,表示為01111110,而尾數1.0去掉整數部分為0,補齊0到23位00000000000000000000000,則其二進位制表示形式為

0 01111110 00000000000000000000000

由上分析可知float型資料最大表示範圍為1.11111111111111111111111*2127=3.4*1038

對於double型資料情況類似,只不過其階碼為11位,偏置量為1023,尾數為52位。

相關指令碼:

自己寫的轉換指令碼(列印十進位制小數的記憶體格式)

import sys,math

def tran1(int_data):
    # 整數部分轉二進位制
    if int_data == 1:
        return int_data
    bit_data = int_data % 2
    int_data = int_data // 2

    return "" + str(tran1(int_data)) + str(bit_data)

def tran2(dec_data):

    # 取整
    bit_data = math.floor(dec_data * 2)
    # 取小數部分
    dec_data = dec_data * 2 - math.floor(dec_data * 2)
    if dec_data == 0:
        return bit_data
    # print(dec_data)
    return ""+str(bit_data)+str(tran2(dec_data))

def insert_space(string, every=8):
    return ' '.join(string[i:i+every] for i in range(0, len(string), every))

def transform(decimal_str,total_bits):
    front_point = int(decimal_str)
    after_point = decimal_str - front_point
    print(front_point,after_point)
    front = tran1(front_point)
    after = tran2(after_point)
    # 符號
    symbols = "1"
    if int(decimal_str) >= 0:
        symbols = "0"
    print("symbols:",symbols)
    # 計算階碼
    n = bin(len(front)-1 + 2**(total_bits-1)-1)[2:].ljust(8,'0')
    print("n:",n)
    # 計算尾數
    binnum = (front[1:]+after).ljust(23,'0')
    print("binnum:",binnum)
    result = symbols+n+binnum
    print(int(result,2))
    print("高位",insert_space(result, every=8))

if len(sys.argv) == 1:
    print("輸入小數轉換成二進位制格式")
else:
    decimals = sys.argv[1:]
    for d in decimals:
        transform(float(d),8)

python的一些庫也能簡單實現:

import struct
import binascii

def float_to_binary(f):
    # 將浮點數打包成位元組物件
    packed = struct.pack('>f', f) # 以大端位元組順序將浮點數打包成位元組物件,沒有>則是小端
    # 將位元組物件轉換為十六進位制字串
    hex_string = binascii.hexlify(packed).decode('utf-8')
    # 將十六進位制字串轉換為二進位制字串
    binary_string = bin(int(hex_string, 16))[2:].zfill(32)
    return binary_string

# 測試
f = 11.28125
binary = float_to_binary(f)
print("Float:", f)
print("Binary:", binary)

'''
Float: 11.28125
Binary: 01000001001101001000000000000000
'''

參考:
https://www.cnblogs.com/dolphin0520/archive/2011/10/02/2198280.html
https://www.runoob.com/w3cnote/decimal-decimals-are-converted-to-binary-fractions.html

相關文章