C# 從補碼中獲取有符號數的實際數值

C# 從補碼中獲取有符號數的實際數值

原理

計算機存儲數據時,默認是存儲數據的補碼。有符號的數粗存在符號位(最高位)。

這裏就會提到原碼、反碼、補碼的概念。

原碼:用符號位和數值表示帶符號數,正數的符號位用“0”表示,負數的符號位用“1”表示,數值部分用二進制形式表示。
反碼:正數的反碼與原碼相同,負數的反碼爲對該數的原碼除符號位外各位取反。
補碼:正數的補碼與原碼相同,負數的補碼爲對該數的原碼除符號位外各位取反,然後在最後一位加1.

思路

下位機上傳有符號數時,直接上傳的是補碼。上位機解析時,需要手動轉換:

一、當數爲負數時。

0.獲取該數據的補碼,去掉最高位(符號位)並將其合併到一個結構體中(數據通信一般以字節爲單位)。

1.空位(不用的位)補全,高位不用的置1。

2.將補碼-1

3.然後再取反

4.乘上比例尺與-1

二、當數爲正數時。

0.獲取該數據的補碼,去掉最高位(符號位)並將其合併到一個結構體中(數據通信一般以字節爲單位)。

1.乘上比例尺

示例

下位機上傳的數據中有8個字節,其中第4(從0開始)字節的低四位和第5字節的高7位組成一個參數,這個參數是有符號的數據,與整數之間的比例尺是0.1。要求解析出該參數。

代碼

 				// 獲取數據
                byte[] data = new byte[8];
                data = GetDataFromUsb();

                // 解析數據
                // 當上傳的數據爲負數時
                if ((UInt16)(data[4] & 0x08) == 0x08)
                {
                    // 去掉最高位獲取數據
                    UInt16 s = (UInt16)(((data[4] & 0x07) << 7) + (UInt16)((data[5] >> 1) & 0x7F));

                    // 空位補全,高位不用的置1
                    UInt16 s1 = (UInt16)(s | 0xFC00);

                    // 補碼-1
                    UInt16 s2 = (UInt16)(s1 - 1);

                    // 取反
                    UInt16 s3 = (UInt16)~s2;

                    // 乘上-1和比例尺
                    _Speed = -(s3 * 0.1f);
                }
                // 當待解析的數據爲正數時
                else
                {
                    // 去掉最高位獲取數據
                    UInt16 s = (UInt16)(((data[4] & 0x07) << 7) + (UInt16)((data[5] >> 1) & 0x7F));

                    // 乘上比例尺
                    _Speed = s * 0.1f;
                }

圖表解釋

1._Speed參數的佔位情況。

7 6 5 4 3 2 1 0
data[4] F_Speed _Speed _Speed _Speed
data[5] _Speed _Speed _Speed _Speed _Speed _Speed _Speed

其中data[4]的第3位爲我們符號位,也就是F_Speed。當我們做有符號碼轉換時,可以直接忽略,因爲他不影響我們真實值的改變。

2.空位補全緣由

當我們使用更大的空間來做容器填充數據時,負數的空位補全。

UInt16也就等於2個字節

第0步運算之後,我們數據如下圖所示。

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
_S _S _S _S _S _S _S _S _S _S

我們知道,上面的所有_S的數據都是元數據的補碼,因爲該數是負數,所以我們需要將這個數據的符號位置爲1,其它未使用的位(14、13、12、11、10)也置爲1。這樣我們就可以通過-1再求反碼得到負數的值了。


積跬步以至千里:) (:一陣沒來由的風

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章