最近應用開發的過程中出現了一個小問題,順便記錄一下原因和方法--運算整數
預備知識
對於位運算,大家都很熟習,基本的位操作有與、或、非、異或等等。在口試中經常會出現位運算相干的題,所以我就做了簡單的整理,參考了很多寫的很好的部落格及書籍。
現在簡單說一下,移位運算。
左移運算: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
運算和整數
---------------------------------