7-19下午刷题未知点集合
接著上午有關 X&(X-1)?的另一個例題:
用一個表達式,判斷一個數X是否是2N次方(2,4,8,16,…),不可用循環語句。
[中國臺灣某著名CPU生產公司2007年10月面試題]
解析:2、4、8、16這樣的數轉化成二進制是10、100、1000、10000。如果X減1后與X 做與運算,答案若是0,則X是2N次方。
答案:!(X&(X-1))
?
下午:
1.
基本的優先級需要記住:
指針最優,單目運算優于雙目運算。如正負號。
先算術運算,后移位運算,最后位運算。
邏輯運算最后計算。
?
請特別注意:1 << 3 + 2 && 7等價于 (1 << (3 + 2))&&7.
?
例:
一是類型轉換問題;二是算符的優先級問題。
對于第一個問題:
unsigned char b=~a>>4,在計算這個表達式的時候,
編譯器會先把a和4的值轉換為int類型(即所謂整數提升)后再進行計算,
當計算結果出來后,再把結果轉換成unsigned char賦值給b。
?
對于第二個問題:
因為“~”的優先級高于“>>”和“+”,本題的過程是這樣的:
先對于1010?0101取反0101 1010;再右移
這里有一個問題,是先右移4位再加1呢,還是直接右移5(4+1)位。
因為“+”的優先級高于“>>”,所以直接右移5位。結果是0000 0010。
最后的結果應該是2才對,但把如上的指令放到vs2008中運行,答案居然是250。
?
那么到底是什么地方出了問題?在調試的過程中進入匯編指令。可以看到高級語句轉換為匯編語言以后,是?先執行取反?再位移?的。
我們看到eax是16位的寄存器,于是在機器中
0xA5的寄存中表達是0000 0000 1010 ?0101 ,
取反是1111?1111 0101 1010,
那么右移5位是0000 0111 1111 1010,
由于是unsigned char型的只能表示低8位的數值,即250
?
2.
(x&y)+((x^y)>>1),效果就是求x與y的平均值
把x和y里對應的每一位(指二進制位)都分成三類,每一類分別計算平均值,最后匯總。
?
其中 一類是x,y中對應位?都是1, 用x&y計算其平均值;
一類是x,y中對應位?有且只有一位是1,用(x^y)>>1計算其平均值;
一類是x,y中對應位?均為0, 無須計算。
第一部分:
x,y對應位均為1,相加后再除以2還是原來的數,如兩個00001111相加后除以2仍得00001111。
第二部分:
對應位有且只有一位為1,用“異或”運算提取出來,然后>>1(右移一位,相當于除以2)。
第三部分:
對應位均為零,因為相加后再除以二還是0,所以不用計算。
?
三部分匯總之后就是(x&y)+((x^y)>>1)
這樣可以避免溢出:
假設x,y均為unsigned char型數據(0~255,占用一字節),顯然,x,y的平均數也在0~255之間,但如果直接x+y可能會使結果大于255,這就產生溢出,雖然最終結果在255之內,但過程中需要額外處理溢出的那一位,在匯編中就需要考慮這種高位溢出的情況,如果(x&y)+((x^y)>>1)計算則不會。
?
3.
利用??位運算??實現兩個整數的???加法運算
!!!!!!重點: 異或?常被認作不進位的加法運算
#include <stdio.h> ?
int main(void) { ??
? ? int add(int a,int b); ?
? ? int m,a,b; ?
? ? scanf("%d,%d",&a,&b); ?
? ? m = add(a,b); ?
? ? printf("m=%d",m); ?
? ? return 0; ?
} ?
int add(int a,int b){ ?
? ? if(b == 0) return a;//沒有進位時,完成運算,a為最終和。 ?
? ? int sum,carry; ?
? ? sum = a ^ b;//沒有進位的加法運算 ?
? ? carry = (a & b) << 1;//進位,左移運算。 ?
? ? return add(sum , carry);//遞歸,相加。 ?
} ?
?
注釋:
*? x ^ y :實現不進位的加法,那么我們接下來就要將進位的數據加上,就可以實現了。
*? x & y : 這個操作,即是找出相同位,為什么我們需要找出相同的位呢,因為只 1 & 1 ,這種情況才會? 產生進位,可能有人會想那 0 & 0 呢,這個沒有影響的。
*? (x & y) << 1:為什么要左移呢,其實也很簡單,即然后我們都已經找出需要進位的位,那么說明在該位置的前面一位,應該加上1,所以應該左移1位,就是加上余數
?
4.
有兩個變量a和b,不用“if”、“?:”、“switch”或其他判斷語句,找出兩個數中間比較大的。
?
第一種:
int max = ((a+b)+abs(a-b))/2;
abs是取絕對值。
如果a>b,那么a-b>0,所以表達式就變成了(a+b+a-b)/2=(a+a)/2=a。
如果a<b,那么a-b<0,取絕對值變成-(a-b),所以表達式變成了(a+b-a+b)/2=(b+b)/2=b。
?
第二種:
int c = a-b;
char *strs[2] = {"a large","b large"};
c = unsigned(c)>>(sizeof(int)*8-1);//判斷符號位
?
注釋:
sizeof(int)?字節數
sizeof(int)*8 位數
右移sizeof(int)*8 - 1 符號位
?
該語句的目的是求出c的最高位的值,
當該值為1時,表示c為負數,因此判斷出a小于b。
當該值為0時,表示c為零或者整數,因此判斷出a大于等于b
?
5.
給三個整數a、b、c,函數實現取三個數的中間數,不可以使用sort,整數操作盡可能少。
(思路:輸入的三個值 中值就是第二大的數值
選中兩個進行比較 找到較大的
較大的與第三個值比較
1.如果較大的 < 第三個值 那這個較大的 就是第二大的數值 就是中值
2.較大的 > 第三個值 ?比較第三個值與 較小的值
1.第三個值 > 較小的值 第三個值 是中值
2.第三個值 < 較小的值 較小的值 是中值)
注意等于號
int median( int a, int b, int c )
{
int min,max;
if ( a < b )
{
min = a;
max = b;
}
else
{
min = b;
max = a;
}
// 此時有 min<=max
if ( max <= c )
return max;
else // min <= max, c <max,
{
// 比較min和c
if ( min <= c ) // min <=c < max
return c;
else
return min; // c< min <= max
}
}
?
6.
如何將a、b的值進行交換,并且不使用任何中間變量?
(單純的加減交換會有溢出的可能 盡量用異或)
void swap(int& a, int& b) //使用位運算也可以交換兩個值
{
a = a^b;
b = a^b;
a = a^b;
}
?
7.
評價一下C與C++的各自特點。如果一個程序既需要大量運算,又要有一個好的用戶界面,還需要與其他軟件大量交流,應該怎樣選擇合適的語言?
因為C++是面向對象的,在封裝、繼承、多態這些特性上,會有比較大的開銷,所以單從運行效率而言,C更適合一些。
但是和C++相比,C的圖形庫相對而言種類比較少,而且比較簡單,所以在比較復雜的界面設計上,C++會更有優勢。因此到底用C還是C++并沒有并且的答案,如果目標平臺的硬件性能比較弱,并且GUI界面比較簡單,推薦用C,反之推薦C++。
總結
以上是生活随笔為你收集整理的7-19下午刷题未知点集合的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有关windows 10自动更新 永久关
- 下一篇: 7-19晚牛客网刷题未知点、错题 集合