public class Test6
{
public static void main(String[] args)
{
//位運算符
// << 左移運算符
//5 的二進制是 0000 0101
//左移一位的話0000 1010
//5 左移一位是10,是不是相當於5*2
System.out.println(5 << 1);
//3左移一位正好是6
System.out.println(3 << 1);
//3左移兩位是12,也就是*4
System.out.println(3 << 2);
//對比下,其實這個表達式跟上方的位移的結果
//是一致的,運算效率上卻要慢很多,這裏只是
//描述下,左移相當於乘上2的幾次冪
System.out.println((int)(3 * Math.pow(2, 2)));
//下邊發現左移0和32還是5,爲什麼呢?
System.out.println(5 << 0);
System.out.println(5 << 32);
//木哈哈,這個絕對大殺器,爲什麼-1是31,-2是30?
System.out.println(5 << -1);
System.out.println("====================================>");
//打印一下x的位移情況,發現左移32位,x還是
//原值,爲什麼會這樣?
//分析下最後幾行,發現,並不是逐位補位的,
//最後一行的像突然插進去的一樣。
int x = 7;
for (int shift = 0; shift <= 32; shift++)
{
System.out.println(getIntegerToBinary(x << shift));
}
System.out.println("====================================>");
//到這裏可以看見,貌似從32開始,又開始像0-31
//那樣子逐位位移了,到第64次的時候又會在繼續
//這看起來是不是像模運算呢?
//其實這不難理解,比如沒有這個現象的話,咱就單
//說位移,32位之後就都是0了吧,顯然沒有意義,
//對於一個int的有效位移次數僅是0-31
System.out.println(getIntegerToBinary(x << 33));
System.out.println("====================================>");
//事實證明,猜想是對的,但問題是,真的是這樣?
//模運算是很慢的,如果真是這樣,位移操作還能比
//乘法快?
for (int shift = 0; shift <= 32; shift++)
{
System.out.println(getIntegerToBinary(x << shift % 32));
}
System.out.println("====================================>");
//既然有效位移次數是0-31,那麼31的2進制是什麼?
//是11111五個一,咱是不是只需要拿到位移次數的
//低五位就可以了?你可以打印下0-64的2進制,看看
//後5位是什麼情況
//如果這個實在難以理解,你就當成是32進制,每次取
//這個數的32進制的個位數
for (int shift = 0, mask = 0x0000001f; shift <= 32; shift++)
{
System.out.println(getIntegerToBinary(x << (shift & mask)));
}
System.out.println("====================================>");
//這個眼熟不?如果 % 的方式是對的?左移-1位你怎麼
//解釋?當然你理解成0相當於32,-1相當於31這是可以
//但是,你怎麼解釋-1和31的關係?有什麼證據?
//總不能說-1%32是31,那還不讓人笑掉大牙?
//-1 & 0x0000001f是多少?取後五位正好是31
System.out.println(getIntegerToBinary(x << (-1 % 32)));
System.out.println(getIntegerToBinary(x << (-1 & 0x0000001f)));
//將上邊的兩行化簡,最後就是這樣的了,結果一樣,那
//也就是說-1被處理,跟%沒有一毛錢關係,問題發生在
//-1怎麼變成31,呵呵,已經很明顯了吧?
System.out.println(getIntegerToBinary(x << -1));
System.out.println(getIntegerToBinary(x << 31));
System.out.println("====================================>");
//這個足夠看出來3種位移方式的區別了
//至於?的運算符,+ ^ |三種都行
//就是個孔雀開屏而已
for (int shift = 1; shift < Integer.SIZE; shift++)
{
System.out.print(getIntegerToBinary(-1 << shift));
System.out.print(" ? " + getIntegerToBinary(-1 >>> Integer.SIZE - shift));
System.out.println(" = " +getIntegerToBinary(-1 >> shift));
}
System.out.println("====================================>");
//上邊的另外一種實現方式
int a = -1;
for (int i =1;i<32; i++)
{
a=a<<1;
System.out.println(getIntegerToBinary(a)+" ^ "
+getIntegerToBinary(~a)+" = "
+getIntegerToBinary(a+~a));
}
System.out.println("====================================>");
}
public static final String DEFAULT_INT_ZERO = "00000000000000000000000000000000";
public static final String getIntegerToBinary(int value)
{
String binary = Integer.toBinaryString(value);
int length = Integer.SIZE - binary.length();
return DEFAULT_INT_ZERO.substring(0, length) + binary;
}
}
複習筆記5 位運算符 以及位移超出整數類型邊界的回滾原理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.