zoukankan      html  css  js  c++  java
  • 运算整数C/C++位运算技巧

    最近应用开发的过程中出现了一个小问题,顺便记录一下原因和方法--运算整数

        

    预备知识

        对于位运算,大家都很熟习,基本的位操作有与、或、非、异或等等。在口试中经常会出现位运算相干的题,所以我就做了简单的整理,参考了很多写的很好的博客及书籍。

        现在简单说一下,移位运算。

        左移运算:x << y。将x左移y位,将x最左边的y位丢弃,在右边补y个0。

        右移运算:x >> y。将x右移y位,这须要区分x是有符号数还是无符号数。在x是无符号数时,只需将x的最右边的y位丢弃,在左边补上y个0。在x是有符号数时,又分为x是正数还是正数。正数时,同无符号数的处置相同;正数时,将将x的最右边的y位丢弃,在左边补上y个1。

        

        

    位运算技巧

        

    盘算一个数的二进制中1的个数

        通过与初始值为1的标志位进行与运算,判断最低位是否为1;然后将标志位左移,判断次低位是否为1;一直这样盘算,直到将每一位都判断终了。

    /*
    	盘算一个数的二进制中1的个数
    */
    int countOf1(int num)
    {
    	int count = 0;
    	unsigned int flag = 1;
    
    	while(flag)
    	{
    		if(num & flag)
    		{
    			count++;
    		}
    
    		flag = flag << 1;
    	}
    	return count;
    }

        还有一种方法,一个整数减一,可以失掉该整数的最右边的1变成0,这个1右边的0变成1。对这个整数和整数减一进行与运算,将该整数的最右边的1变成0,其余位坚持稳定。直到该整数变成0,进行的与运算的次数即为整数中1的个数。

    /*
    	盘算一个数的二进制中1的个数
    */
    int countOf1_2(int num)
    {
    	int count = 0;
    
    	while(num)
    	{
    		num = num & (num - 1);
    		count++;
    	}
    	return count;
    }

        

    判断一个数是否是2的n次方

        一个数是2的n次方,则这个数的最高位是1,其余位为0。根据上一题的第二种解法可以很轻易失掉解决方案。将这个整数与整数减一进行与运算,如果失掉的结果为零,可证明该数为2的n次方。

    /*
    	判断一个数是否为2的n次方(一个数为2的n次方,则最高位为1,其余位为0)
    */
    bool is2Power(int num)
    {
    	bool flag = true;
    
    	num = num & (num - 1); //盘算num和num - 1的与的结果
    	if(num) //如果结果为0,则不是2的n次方
    	{
    		flag = false;
    	}
    	
    	return flag;
    }

        

    整数n经过多少步可以变成整数m

        n和m的异或结果可以得悉两数不同位的个数,再调用盘算一个数中1的个数的方法,即可失掉结果。

    /*
    	求解n变化为m,须要进行的操作步数
    */
    int countChange(int n,int m)
    {
    	n = n ^ m; //求n和m的异或,再盘算结果中1的个数
    	return countOf1_2(n);
    }

        

    取得最大的int值

    /*
    	获取最大的int
    	失掉结果:2147483647
    */
    int getMaxInt()
    {
    	return (1 << 31) - 1;
    }
    
    /*
    	应用g++编译,出现warning: left shift count is negative
    */
    int getMaxInt_2()
    {
    	return (1 << -1) - 1;
    }
    
    int getMaxInt_3()
    {
    	return ~(1 << 31);
    }
    
    /*
    	在不了解int的长度情况下应用
    */
    int getMaxInt_4()
    {
    	return ((unsigned int) -1) >> 1; 
    }
        每日一道理
    喜欢海,不管湛蓝或是光灿,不管平静或是波涛汹涌,那起伏荡漾的,那丝丝的波动;喜欢听海的声音,不管是浪击礁石,或是浪涛翻滚,那轻柔的,那澎湃的;喜欢看海,不管心情是舒畅的或是沉闷的,不管天气是晴朗的或是阴沉的,那舒心的,那松弛的……

        

    取得最小的int值

        与取得最大的int方法相似。

    /*
    	求最小int
    	失掉结果:-2147483648
    */
    int getMinInt()
    {
    	return 1 << 31;
    }
    
    /*
    	同样在g++下编译,出现warning: left shift count is negative
    */
    int getMinInt_2()
    {
    	return 1 << -1;
    }

        

        

    取得最大的long

    /*
    	求最大long
    	失掉结果:9223372036854775807
    */
    long getMaxLong()
    {
    	return ((unsigned long) -1) >> 1;
    }

        

    判断一个数的奇偶性

        判断奇偶性,实质是判断最后一位是否是1.

    /*
    	判断一个数的奇偶性.返回1,为奇数;返回0,为偶数
    */
    bool isOdd(int num)
    {
    	return num & 1 == 1;
    }

        

    交换两个数(不借助第三变量)

        不必第三个变量交换两个数的方法也有几种,例如a = a + b;  b = a - b; a = a - b。下面这类方法可以实现的基本是一个数m与另一个数n异或,再与n异或,失掉的结果是m.

    /*
    	不实用临时变量,交换两个数
    	a = a ^ b
    	b = b ^ a
    	a = a ^ b
    */
    void mySwap(int* a,int* b)
    {
    	(*a) ^= (*b) ^= (*a) ^= (*b);
    }

        

    求一个数的绝对值

        下面的方法实现的基本是将n右移31位,可以取得n的符号。

    /*
    	取绝对值
    	n右移31位,可以取得n的符号。若n为正数,失掉0;若n为正数,失掉 -1
    	
    */
    int myAbs(int n){
    	return (n ^ n >> 31) - (n >> 31);
    }

        

    求两个数的平均值

        第一种方法较为广泛且简单,不多说了。第二种方法,须要晓得的是,( m ^ n ) >> 1失掉的结果是m和n其中一个数的有些位为1的值的一半,m & n失掉的结果是m 和n都为1的那些位,两个结果相加失掉m和n的平均数。

    /*
    	求m和n的平均数
    */
    int getAverage(int m,int n){
    	return (m + n) >> 1;
    }
    
    /*
    	求m和n的平均数
    	(m ^ n) >> 1 -> 取得m和n两个数中一个数的某些位为1的一半
    	m & n -> 取得m和n两个数中都为1的某些位
    */
    int getAverage_2(int m,int n){
    	return ((m ^ n) >> 1) + (m & n);
    }

        

    求解倒数第m位相干问题

    /*
    	获取n的倒数第m位的值(从1开始计数)
    */
    int getMthByTail(int n,int m){
    	return (n >> (m - 1)) & 1;
    }
    
    /*
    	将n的倒数第m位设为1
    */
    int setMthByTail21(int n,int m)
    {
    	return n | (1 << (m - 1));
    }
    
    /*
    	将n的倒数第m位设为0
    */
    int setMthByTail20(int n,int m)
    {
    	return n & ~(1 << (m - 1));
    }

    文章结束给大家分享下程序员的一些笑话语录: 警告
    有一个小伙子在一个办公大楼的门口抽着烟,一个妇女路过他身边,并对他 说, “你知道不知道这个东西会危害你的健康?我是说, 你有没有注意到香烟 盒上的那个警告(Warning)?”
    小伙子说,“没事儿,我是一个程序员”。
    那妇女说,“这又怎样?”
    程序员说,“我们从来不关心 Warning,只关心 Error”

    --------------------------------- 原创文章 By
    运算和整数
    ---------------------------------

  • 相关阅读:
    UiPath实践经验总结(二)
    UiPath针对SAP的输入技巧
    UiPath如何实现暂停功能?
    设计模式 设计原则实现高内聚低耦合的编程思想
    SpringBoot整合Swagger自动生成API文档
    ArcGis10.1安装及破解
    EAT表
    IAT表
    PE文件介绍 (2)-DOS头,DOS存根,NT头
    PE文件介绍 (1)
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3112925.html
Copyright © 2011-2022 走看看