C#位運算實際運用之合並Int


c#位運算系列

前言

最后提到一個實際問題

  • 需求:C# 用兩個short,一個int32拼成一個long型

  • 要求:現在有兩個short和一個int,需要拼成一個long型,高16位用short,中間32位用int,最低16位用另外一個short
    https://bbs.csdn.net/topics/392202825?page=1

  • 答案:((long)shortA << 48 )+ ((long)intA << 16)+ shortB=longResult

  • 我提出的疑問:能不能根據longResult反推出shortA、intA、shortB

  • 我當時的回答:是一個極其錯誤的答案,原文片段如下
    那么疑問來了可以通過longResult返推出shortA,shortB,intA。當然是不能這是直接相加。
    返回不應該用這種組合字符串的方式
    ((long)shortA << 48 ) 16位二進制0或1的字符串
    ((long)intA << 16) 32位二進制0或1的字符串
    shortB 16位二進制0或1的字符串
    將這三個字符串拼接成64位二進制字符串,再將這個64位二進制字符串轉成一個long

    當然這種方式得到的結果是沒毛病的,分割二進制的位數,對應去設置0或1。但是做法太草率,沒有動腦筋,這種做法效率太低。
    正確的做法根據longResult算出shortA、intA、shortB也是要用位運算的。

1.為什么我要記錄下來

有很多最基本的知識點,沒有了解到,在遇到錯誤的時候,會走不少彎路,浪費很多不應該浪費的時間。說簡單點,基礎知識不牢固,工作效率低。
比如:一個二進制數的第一位是從左邊開始算,還是從右邊開始算起?
我深信讀到這里的人,至少有一部分人不知道。當然,我也是屬於這一部分人。(我並不想直接說出答案,可能會猜到有點人打開了百度)
為什么要記錄下來?因為今天提交了一段垃圾代碼關於整型合並的相互轉換。領導看了,很沉默,不說話,發了篇文章給我,讓我看,修改一下。其實我提交那段垃圾代碼的時候心里就很沒底懸得慌,感覺這樣做很不合適。學而時習之,溫故而知新。

2.兩個short一個int如何合並一個long?

需求:
高16位用short,中間32位用int,最低16位用另外一個short。
答案:((long)shortA << 48 )+ ((long)intA << 16)+ shortB
具體的計算過程是這樣的
距離shortA 是 17,intA是8,shortB是20
17是short類型 16位的二進制

0000	0000	0001	0001

8是int類型 32位的二進制

0000	0000	0000	0000
0000	0000	0000	1000

20是short類型 16位的二進制

0000	0000	0001	0100

從這個三個二進制就可以得出long類型的64位二進制,long值是4785074604605460

0000	0000	0001	0001
0000	0000	0000	0000
0000	0000	0000	1000
0000	0000	0001	0100

step1:將shortA 17的二進制左位移48位也就是這個long類型最左邊16位(17一定要先轉成long再左位移,一定要記住這一點)
(long)17<<48 的結果是4785074604081152 17乘以2的48次方法
2的49次方(第一個1在49位)加上2的53次方(第二個1在53位)
17的64位二進制

0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0001	0001

向左移動48位后

0000	0000	0001	0001
0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	0000

step2:8的二進制左移16位,(long)8<<16的結果是:524588
8的64位二進制

0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	1000

向左移動16位后

0000	0000	0000	0000
0000	0000	0000	1000
0000	0000	0000	0000
0000	0000	0000	0000

step3 :
(long)17<<48 +(long)8<<16 =4785074604081152 +524588
有效位數已經占滿了前48位,剩下的有效16位就是20
最終的結果就是
((long)8<<16)+((long)17<<48)+20 =4785074604605460

3.根據long如何反推出合並前的兩個short和一個int

完美三部曲,干就完事了。
step1:首先要獲取前16位有效值shortA
我們已經知道了longResult 4785074604605460的64位二進制

0000	0000	0001	0001
0000	0000	0000	0000
0000	0000	0000	1000
0000	0000	0001	0100

將這個long類型往右移動48位得到的64位二進制,也就是16位有效值shortA,這個short就是17

0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0001	0001

longResult >>48完美得到shortA的值17,右位移也就是longResult整除2的48次方
shortA =(short)(longResult<<48)

step2:然后獲取中間32位intA的值,先將這個longResult右位移16位,得到后48位有效值

0000	0000	0000	0000
0000	0000	0001	0001
0000	0000	0000	0000
0000	0000	0000	1000

現在要取的后面32位有效值才是intA的值,再將(longResult>>16)&0xFFFFFFFF,做邏輯與運算,0xFFFFFFFF(4294967295,這是一個UInt32類型,有效位的32位全部是1)的64位二進制

0000	0000	0000	0000
0000	0000	0000	0000
1111	1111	1111	1111
1111	1111	1111	1111

與運算的規則1&1=1 、1&0=0、0&0=0,所以對后48位有效值做完邏輯與運算,就得到有效32位的intA

0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	1000

intA=(int)((longResult>>16)&0xFFFFFFFF)
intA的最終結果就是8

step3:最后獲取最右邊16位的shortB(將前面48位都變成0),只需要做一次與運算就可以,longResult做與運算的對象是0xFFFF(65535),有效16位全部都是1,二進制如下

0000	0000	0000	0000
0000	0000	0000	0000
1111	1111	1111	1111
1111	1111	1111	1111

longResult&0xFFFF的最終結果就是20

0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0000	0000
0000	0000	0001	0100

shortB=(short)(longResult&0xFFFF)=20;

4.總結

高16位用short,中間32位用int,最低16位用另外一個short。

longResult=((long)shortA << 48 )+ ((long)intA << 16)+ shortB

根據longResult獲取前16位shortA,中間32位intA,后16位shortB

shortA=(short)(longResult>>48)
intA=(int)((longResult>>16)&0xFFFFFFFF)
shortB=(short)(longResult&0xFFFF)

那么
想用一個byte存兩個數,如何相互轉換?
如何獲取和設置一個int的二進制位?
知道計算過程和位運算的基本概念,這些問題就非常簡單,會者不難,難者不會。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM