前言

前几天写了一篇关于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,这是一个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的二进制位?

知道计算过程和位运算的基本概念,这些问题就非常简单,会者不难,难者不会。

有兴趣关注一下我的个人公众号,谢谢

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

  1. Java 位运算2-LeetCode 201 Bitwise AND of Numbers Range

    在Java位运算总结-leetcode题目博文中总结了Java提供的按位运算操作符,今天又碰到LeetCode中一道按位操作的题目 Given a range [m, n] where 0 <= ...

  2. 简简单单学会C#位运算

    一.理解位运算 要学会位运算,首先要清楚什么是位运算?程序中的所有内容在计算机内存中都是以二进制的形式储存的(即:0或1),位运算就是直接对在内存中的二进制数的每位进行运算操作 二.理解数字进制 上面 ...

  3. SQL Server时间粒度系列----第8节位运算以及设置日历数据表节假日标志详解

    本文目录列表: 1.位运算 2.设置日历数据表节假日标志 3.总结语 4.参考清单列表   位运算   SQL Server支持的按位运算符有三个,分别为:按位与(&).按位或(|).按位异或 ...

  4. js中的位运算

    按位运算符是把操作数看作一系列单独的位,而不是一个数字值.所以在这之前,不得不提到什么是"位": 数值或字符在内存内都是被存储为0和 1的序列,每个0和1被称之为1个位,比如说10 ...

  5. Java中的位运算

    昨天去面试的时候做到了一道Java的位运算题目,发现有个运算符不懂:">>>",今天特地查了一下,并小结一下常见的位运算符号: ~  按位非(NOT)(一元运算) ...

  6. C#位运算讲解与示例

    首先每一个权限数都是2的N次方数 如:k1=2 ; //添加 k2=4 ; //删除 k3=8; //修改 ... 如此定义功能权限数,当需要组合权限时,就需要对各个所拥有的权限数按位或了. 如: p ...

  7. C#枚举中的位运算权限分配浅谈

    常用的位运算主要有与(&), 或(|)和非(~), 比如: 1 & 0 = 0, 1 | 0 = 1, ~1 = 0 在设计权限时, 我们可以把权限管理操作转换为C#位运算来处理. 第 ...

  8. Java位运算经典实例

    一 源码.反码.补码 正数的源码.反码.补码相同,例如5:            5的源码:101            5的反码:101            5的补码:101 负数的源码.反码.补 ...

  9. C入门---位运算

    程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算直接对整数在内存中的二进制位进行操作.由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快. (1),与(&)运算 ...

  10. EF架构~为分组添加位运算聚合方法

    回到目录 我们知道在Linq里的分组groupby可以对集合中一个或者多个字段进行分组,并对其中一个属性进行聚合,而Linq为我们提供了多种聚合方法,由aver,sum,count等,而在大叔权限体系 ...

随机推荐

  1. 7种html5css3网页图片展示特效代码

    鼠标拖拽图片渐变透明切换特效 mobile手机左右滑动切换幻灯片 游戏透明提示图层幻灯片特效 可以编辑滚动条灯片颜色的scroll插件 几种文字动画显示插件代码 360度背景图片旋转的css3动画 左 ...

  2. input 输入框 change 事件和 blur 事件

    输入框的 change 和 blur  事件绝大多数情况下表现是一致的,输入结束后离开输入框会先后触发 change 和 blur.那么这两个事件的区别在哪呢? 当文本框获得焦点后,没有输入任何内容, ...

  3. Android Studio_更新Gradle

    一.Gradle更新问题 Android Studio每次更新版本都会更新Gradle这个插件,而且有时候提示更新,却一直更新不了,那是因为中国伟大的长城问题.就是下图,我刚刚更新了,提示更新grad ...

  4. 【Java入门提高篇】Day30 Java容器类详解(十二)TreeMap详解

    今天来看看Map家族的另一名大将——TreeMap.前面已经介绍过Map家族的两名大将,分别是HashMap,LinkedHashMap.HashMap可以高效查找和存储元素,LinkedHashMa ...

  5. 利用奇异值分解(SVD)进行图像压缩-python实现

    首先要声明,图片的算法有很多,如JPEG算法,SVD对图片的压缩可能并不是最佳选择,这里主要说明SVD可以降维 相对于PAC(主成分分析),SVD(奇异值分解)对数据的列和行都进行了降维,左奇异矩阵可 ...

  6. aws s3文件上传设置accesskey、secretkey、sessiontoken

    背景: 最近跟进的项目会封装aws S3资源管理细节,对外提供获取文件上传凭证的API,业务方使用获取到的凭证信息直接请求aws进行文件上传.因此,测试过程需要验证S3文件上传的有效性.aws官网有提 ...

  7. TensorFlow 安装教程

    1.准备好Anaconda环境 tensorflow是属于很高层的应用.高层应用的一个比较大的麻烦就是需要依赖的底层的东西很多,如果底层依赖没有弄好的话,高层应用是没法玩转的. 在极客学院有关tens ...

  8. 洗礼灵魂,修炼python(62)--爬虫篇—模仿游戏

    前言 <模仿游戏>这个电影相信如果你是搞IT的,即使没看过也听过吧?电影讲述了计算机之父——阿兰-图灵的一些在当时来讲算是计算机史里的里程碑事迹了.而[模仿游戏]这个名字咋一看,貌似和电影 ...

  9. const int *p 和int * const p 的区别

    看例子: int sloth = 3; const int *p1 = &sloth; int * p2 const = &sloth; 这样申明的话,不允许使用p1来修改sloth的 ...

  10. 上下文管理器——with语句的实现

    前言 with语句的使用给我们带来了很多的便利,最常用的可能就是关闭一个文件,释放一把锁. 既然with语句这么好用,那我也想让我自己写的代码也能够使用with语句,该怎么实现? 下面具体介绍怎样实现 ...