C#位运算实际运用

前言

前几天写了一篇关于c#位操作,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)的64位二进制全部都是1

1111    1111    1111    1111
1111    1111    1111    1111
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的二进制位?
知道计算过程和位运算的基本概念,这些问题就非常简单,会者不难,难者不会。

原文地址:https://www.cnblogs.com/zhangmumu/p/10793689.html

时间: 2024-08-13 22:05:06

C#位运算实际运用的相关文章

位运算

位运算的实际应用场景 http://blog.csdn.net/zmazon/article/details/8262185

POJ 1781 In Danger Joseph环 位运算解法

Joseph环,这次模固定是2.假设不是固定模2,那么一般时间效率是O(n).可是这次由于固定模2,那么能够利用2的特殊性,把时间效率提高到O(1). 规律能够看下图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2VuZGVuMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > 具体具体解析请看大师Knuth的Concrete m

位运算总结&amp;拾遗

JavaScript 位运算总结&拾遗 最近补充了一些位运算的知识,深感位运算的博大精深,此文作为这个系列的总结篇,在此回顾下所学的位运算知识和应用,同时也补充下前文中没有提到的一些位运算知识. 把一个数变为大于等于该数的最小的2的幂 一个数为2的幂,那么该数的二进制码只有最高位是1. 根据这个性质,我们来举个栗子,比如有数字10,转为二进制码后为: 1 0 1 0 我们只需把 0 bit的位置全部用1填充,然后再把该二进制码加1就ok了.而x | (x + 1)正好可以把最右边的0置为1,可是

Java I/O : Bit Operation 位运算

Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆         瓣:BYSocket FaceBook:BYSocket Twitter    :BYSocket 泥瓦匠喜欢Java,文章总是扯扯Java. I/O 基础,就是二进制,也就是Bit. 一.Bit与二进制 什么是Bit(位)呢?位是CPU处理或者数据存储最小的单元.类似于很小很小的开关,一开一关,表示为1或者0.所以,这就是计算机处理任何数据的"细胞",要谨记.

mysql位运算

1.MOD(X1,X2) 求余运算,返回余数同"%" 2.X1 DIV X2 除法运算返回商,同"/" 3.如果除数为0,那么结果为NULL. 4.<=>和= 是一样的,也是用来判断操作数是否相等的.不同的是<=>可以用来判断null,=不能判断null. 例:select null<=>null 结果1 逻辑运算符 1.与&&或and:所有操作数不为0且不为null时,结果为1,任何一操作数为0,结果为0,存在一

位运算之 C 与或非异或

位运算比较易混: 位运算之 C 与或非异或 与运算:& 两者都为1为1,否则为0 1&1=1,  1&0=0,  0&1=0,  0&0=0 或运算:| 两者都为0为0,否则为1 1|1 = 1,  1|0 = 1,  0|1 = 1, 0|0 = 0 非运算:~ 1取0,0取1 ~1 = 0, ~0 = 1 ~(10001) = 01110 异或运算:^ 两者相等为0,不等为1(易混淆) 1^1=0, 1^0=1, 0^1=1, 0^0=0 位移操作符:<&

Java的位运算

左移位操作 左移位运算的符号为[<<],左移位运算符左面的操作元称作被移位数,右面的操作数称作移位量. 左移位运算是双目运算符,操作元必须是整型类型的数据,其移动过程是:[a << n]运算的过程是通过将a的所有位都左移n位,每左移一个位,左边的最高位上的0或1被移出丢弃,并用0填充右边的低位 注意: 如果a是byte.short或int型数据,总是先计算出n%32的结果m,然后进行a<<m运算 对于long型数据,总是先计算出n%64的结果m,然后进行a <&l

常见的位运算

位运算主要有:|   &   ^    ~ & 这个是只要有0,则0 | 这个只要有1,则1 ^异或运算,只要不同则为1 ~全部相反 参与位运算首先要将数值化作为二进制补码,方可参与运算 >>                                               >>>                                << 有符号右移                                无符号右移   

C位运算笔记(根据网上内容整理)1

什么是位运算?    程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算说穿了,就是直接对整数在内存中的二进制位进行操作.由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快. 各种位运算的使用 === 1. and运算 ===(同真为真) and运算通常用于二进制取位操作,例如一个数 and 1的结果就是取二进制的最末位.这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数. === 2. or运算 ===(一真为真) or运算通

位运算和关于两个数交换的多种方法

我们知道,位运算在计算中有着广泛的应用. 在计算机的各种编程语言中位运算也是一种不可缺少的运算,尤其是在计算机的底层实现代码中. 以下我们就来介绍一下位运算. 1.左移运算<<  左移右移都是移动二进制数 0000-0000 0000-0000 0000-0000 0000-1100     =12 向左移动一位变为(右边缺几位就补几个0) 0000-0000 0000-0000 0000-0000 0001 1000       =24 再向左移一位 0000-0000 0000-0000