利用位運算計算某種資料型別的最大值和最小值
阿新 • • 發佈:2019-02-07
- 常見數值的補碼
數值
補碼
0
0000 0000
1
0000 0001
-1
1111 1111
-256
1000 0000
255
0111 1111
最高位是符號位,0表示正數,1表示負數。
- 已知負數求補碼
方法:將對應絕對值的補碼按位取反,然後加上1,比如求-1的補碼,先取1的補碼:0000 0001 1 按位取反 1111 1110 加上1 1111 1111 -1 - 已知負數的補碼,求負數
方法:補碼-1,然後按位取反得到絕對值,然後加上負號
也可以直接按位取反,得到絕對值加上1,然後加上負號1111 1111 減去1 1111 1110 按位取反 0000 0001 1 加上負號 -1
再如:1111 1111 按位取反 0000 0000 0 加上1 1 填上負號 -1 1000 0000 按位取反 0111 1111 127 加上1 128 填上負號 -128 - 最大值和最小值的特徵
從以上補碼,可以看出,任何一種資料型別,其最大值的特點是最高位為0,其餘為均為1,而最小值,其特點是最高位為1,其餘位均為0。因此對於任何一種資料型別,只要通過位移運算,得到符合上述特點的補碼就可以獲取到相應資料型別的最大值和最小值。現假設要計算短整型的資料範圍,則其最大值和最小值的補碼如下:255 0111 1111 -256 1000 0000 32768 0111 1111 1111 1111 -32769 1000 0000 0000 0000
要獲得以上補碼,我們可以看到,最簡單的是獲得最小值的補碼,它可以通過對1左移15位獲得,而如果獲得了最小值的補碼,那麼按位取反,就可以獲得最大值的補碼,過程如下:最大值 0111 1111 1111 1111 最小值 1000 0000 0000 0000 0000 0000 0000 0001 1 左移15位 1000 0000 0000 0000 -32769 按位取反 0111 1111 1111 1111 32768
下面是實驗:1<<(sizeof(int)*8-1) -2147483648 ~(1<<(sizeof(int)*8-1)) 2147483647 注意以下差異: (short)(1<<(sizeof(short)*8-1)) -32768 (short)(~(1<<(sizeof(short)*8-1))) 32767 ((short)1)<<(sizeof(short)*8-1) 32768 ~(((short)1)<<(sizeof(short)*8-1)) -32769 ((int)1)<<(sizeof(int)*8-1) -2147483648 ~(((int)1)<<(sizeof(int)*8-1)) 2147483647 ((long)1)<<(sizeof(long)*8-1) -2147483648 ~(((long)1)<<(sizeof(long)*8-1)) 2147483647
於是,對於一個對輸入的整形數乘以一定倍數的模板函式,可以通過下面的方式確定數值範圍:template<typename T> int Test(T x,int nScale) { T nMin = (T)(1<<(sizeof(x)*8-1)); //確定該型別的最大值 T nMax = (T)(~(1<<(sizeof(x)*8-1))); //確定該型別的最小值 int nVal = x*nScale; //乘以一定的倍數 if(nVal<nMin) return nMin; //如果越下界,則返回下界值 else if(nVal>nMax) return nMax; //如果越上界,則返回上界值 else return nVal; //沒有越界,返回乘倍後的值 }