• C#位运算实际作用之操作整型某一位


    c#位运算系列

    1.前言

    在文中也提到了位运算的实际作用之一就是合并整型,当时引用了一个问题:
    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#位运算实际运用
    如图:
    在这里插入图片描述
    这篇文章就将记录两个知识点:
    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>
            /// Int16Int32Int64类型
            /// </summary>
            /// <returns>true 1false 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">泛型类型包括intshortlong</typeparam>
            /// <param name="intVal">intshortlong</param>
            /// <param name="index">从右到左0-T的总位数</param>
            /// <returns>true:1false: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">intshortlong</typeparam>
            /// <param name="intVal">设置前的值</param>
            /// <param name="index">从右到左0-T的总位数</param>
            /// <param name="bitValue">需要设置的值 true:1false: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);
                }
            }
    

    测试截图:
    在这里插入图片描述
    思考:这个方法能操作负数吗?
    有兴趣关注一下我的个人公众号,谢谢

  • 相关阅读:
    MongoDB自学(1)MongoDB4.0安装
    MongoDB自学(3)MongoDB文档操作
    MongoDB自学(2)创建删除数据库及集合
    vsftpd限制下载流量
    关于旧博客迁移到此博客开场白
    WPF DataTemplate與ControlTemplate
    ErlangC 最佳人力效益指标
    MahApps.Metro控件更換微軟視窗主題
    Erlang C 與M/M/N排隊模型
    WPF 正確理解ContentPresenter
  • 原文地址:https://www.cnblogs.com/zhangmumu/p/10805312.html
Copyright © 2020-2023  润新知