1.前言

前几天写了两篇关于c#位运算的文章
c#位运算基本概念与计算过程 <https://www.cnblogs.com/zhangmumu/p/10793689.html>
C#位运算实际运用 <https://www.cnblogs.com/zhangmumu/p/10793689.html>
在文中也提到了位运算的实际作用之一就是合并整型,当时引用了一个问题:
C# 用两个short,一个int32拼成一个long型,高16位用short,中间32位用int,最低16位用另外一个short。
答案如下:
高16位shortA、中间32位intA、低16位shortB
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)
评论者pushouli、czd890 评论到,合并这个long类型的结果是使用加法计算,可以使用位逻辑或运算,想了想确实使用|
位逻辑或运算也是可以解决问题的,能够实现相互转换。

1楼 2019-04-30 07:28 pushouli 简单明了,但感觉合并那里,不应该用加法去算,用|运算符更合适。

11楼 2019-04-30 18:10 czd890

@ pushouli 用+ 和 | 在这里性能上应该没有太大区别。 但是感觉用 | 更能表达意思一些
longResult=(((long)shortA << 48) |((long)intA << 16)) | (long)shortB
1|0=1、1|1=1、0|0=0

其计算结果longResult是一样的,运算方式不一样,其计算过程可以看看前面写的一篇
C#位运算实际运用 <https://www.cnblogs.com/zhangmumu/p/10793689.html>
如图:

这篇文章就将记录两个知识点:
1.负数的二进制位表示法
2.位运算如何直接操作Int类型某一位

2.负数的二进制位表示法

原码:一个整数按照绝对值的大小转换成的二进制数,称为原码
一个short 16位的整数9的原码是:
0000 0000 0000 1001
反码:一个二进制数按位取反,所得的二进制数成为原二进制数的反码
取9的二进制数的反码,可以使用位逻辑非运算 ~
取反后的16位二进制
1111 1111 1111 0110
补码:反码加1称为补码,简而言之,要得到一个属的补码,先得到这个数的反码,然后再将反码加上1,所得数称为补码
那么9的补码也就是
1111 1111 1111 0110
加上1的结果,如下:
1111 1111 1111 0111
即-9的16位二进制表示是
1111 1111 1111 0111
如图:


3.c#Int有符号的和无符号的区别

话不多说,直接明确三点结论:
1.实际开发中,都用的是有符号的Int(应该默认强制要求),只有整型有有无符号的特征,Double、Decimal,是没有这种特征的。
2.无符号数中,所有的位都用于直接表示该值的大小。
3.有符号数中,最高位用于表示正负。
这里还是简单地啰嗦几句关于有符号和无符号的区别,UInt32和Int32的区别
这里说的Int指的是32位有符号的类型
Int32的值范围是 -2147483648 至2147483647,也就是
-2的31次方到2的31次方-1
符号位表示的意义就在于此,最前面的位表示正负。

-2148483648的32位二进制是:
1000 0000 0000 0000 0000 0000 0000 0000
2147483647的32位二进制是:
0111 1111 1111 1111 1111 1111 1111 1111
那么c#中UInt32的最大值是什么呢?
UInt32的范围是0到2的32次方4294967295,最大值32位二进制是
1111 1111 1111 1111 1111 1111 1111 1111
所以得出结论无符号只能表示正数,有符号可以表示正负数。
如图:


4.c#Int如何直接操作每一位

前面已经说到,Int表示的是有符号的,最高位表示的正负,一个Int有32位,虽然我们可以直接操作这32位,但是如果直接操作明显会改变数据类型的正负、最大范围。
这里写了一个泛型的示例,操作整型(int、short、long)的每一位。
/// <summary> /// Int16\Int32\Int64类型 /// </summary> /// <returns>true
1\false 0的集合</returns> public static IEnumerable<bool> GetIntOfBitList<T>(T
intVal) { Type intType = intVal.GetType(); byte bitlength = 0; if (intType ==
typeof(Int32)) bitlength = 32; else if (intType == typeof(Int16)) bitlength =
16; else if (intType == typeof(Int64)) bitlength = 64; else throw new
ArgumentException("必须是整型"); object intOject = (object)intVal; var resultList =
new List<bool>(bitlength); for (var i = 0; i < bitlength; i++) { var temoIntBit
= 1 << i; if (intType == typeof(Int32)) resultList.Add((((Int32)intOject) &
temoIntBit) == temoIntBit); if (intType == typeof(Int16))
resultList.Add((((Int16)intOject) & temoIntBit) == temoIntBit); if (intType ==
typeof(Int64)) resultList.Add((((Int64)intOject) & temoIntBit) == temoIntBit);
} return resultList; } /// <summary> /// 获取T整型中某一位的值 /// </summary> ///
<typeparam name="T">泛型类型包括int\short\long</typeparam> /// <param
name="intVal">int\short\long</param> /// <param
name="index">从右到左0-T的总位数</param> /// <returns>true:1\false:0</returns> public
static bool GetBitValue<T>(T intVal,byte index) { Type intType =
intVal.GetType(); byte bitlength = 0; if (intType == typeof(Int32)) bitlength =
32; else if (intType == typeof(Int16)) bitlength = 16; else if (intType ==
typeof(Int64)) bitlength = 64; else throw new ArgumentException("必须是整型"); if
(index > bitlength-1 || index < 1) throw new
ArgumentOutOfRangeException("index"); object intOject = (object)intVal; var
tempBit = 1 << index; if (intType == typeof(Int32)) return (((int)intOject) &
tempBit) == tempBit; else if (intType == typeof(Int16)) return
(((Int16)intOject) & tempBit) == tempBit; else return (((Int64)intOject) &
tempBit) == tempBit; } /// <summary> /// 设置整型数据中某一位的值 /// </summary> ///
<typeparam name="T">int\short\long</typeparam> /// <param
name="intVal">设置前的值</param> /// <param name="index">从右到左0-T的总位数</param> ///
<param name="bitValue">需要设置的值 true:1\false:0</param> ///
<returns>设置位值后新的整型</returns> public static T SetBitValue<T>(T intVal,byte
index,bool bitValue) { Type intType = intVal.GetType(); byte bitlength = 0; if
(intType == typeof(Int32)) bitlength = 32; else if (intType == typeof(Int16))
bitlength = 16; else if (intType == typeof(Int64)) bitlength = 64; else throw
new ArgumentException("必须是整型"); //不能去设置最高位 if (index >= bitlength-1 || index <
1) throw new ArgumentOutOfRangeException("index"); object intOject =
(object)intVal; var tempBit = 1 << index; if (intType == typeof(Int32)) { int
tempInt = (int)intOject; return (T)((bitValue ? (tempInt | tempBit) : (tempInt
& ~tempBit)) as Object); } else if (intType == typeof(Int16)) { Int16 tempInt =
(Int16)intOject; return (T)((bitValue ? (tempInt | tempBit) : (tempInt &
~tempBit)) as Object); } else { Int64 tempInt = (Int64)intOject; return
(T)((bitValue ? (tempInt | tempBit) : (tempInt & ~tempBit)) as Object); } }
测试截图:

思考:这个方法能操作负数吗?

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信