此文章试图解答以下三个问题:
- 对int类型数据运用位移运算符时,位移距离有何关系时会得到同一结果?其他数值类型呢?
- 对int类型数据运用位移运算符位移与乘以2除以2位移的区别?
- 对int类型数据乘以因子含有「2」的数字多少次会归零化?
第一个问题:
对int类型数据运用位移运算符时,位移距离有何关系时会得到同一结果?
观察以下代码,注意位移位数之间的关系:
//位移部分
int a = 8;
int b = 8;
a = a << 7;
b = b << 39;
int c = 1;
int d = 1;
c = c << 4;
d = d << 36;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
观察输出:
1024
1024
16
16
此种现象与C语言中的循环移位类似,那怎么样的两个数移位相同呢?答案是对32同余的的数,即除32能得到同一余数的数。
同余:数论中的重要概念。给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b)/m得到一个整数,那么就称整数a与b对模m同余,记作a≡b(mod m)。对模m同余是整数的一个等价关系。(同余_百度百科)
int类型是对模32同余的数循环位移的,那是否short类型是与模16同余的数结果相同?byte是与模8同余的呢?
测试:
short a = 8;
short b = 8;
a = (short) (a << 1);
b = (short) (b << 17);
short c = 1;
short d = 1;
c = (short) (c << 6);
d = (short) (d << 22);
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
输出:
16
0
64
0
//并非如推测所言
由代码可看出所有运算被提升到int类型范围上运算,因此可以可得出在比int小的数字类型上循环位移相同条件仍然是:与32同余. 那,long类型呢?
测试:long类型用32同余数测试
//long类型
long a = 8;
long b = 8;
a = a << 1;
b = b << 33;
long c = 1;
long d = 1;
c = c << 6;
d = d << 38;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
//输出:
16
68719476736
64
274877906944
//32不行
long类型用同64同余数测试:
//long类型
long a = 8;
long b = 8;
a = a << 1;
b = b << 65;
long c = 1;
long d = 1;
c = c << 6;
d = d << 70;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
//输出:
16
16
64
64
//与64同余的数,可得到相同位移数
结论:
int类型和比它小的数值类型进行移位符运算,当两个数对模32同余时可得到同一结果,且为循环移位。long数值类型进行移位符运算,当两个数对模64同余时可得到同一结果,且为循环移位。由此引出下一个问题:
第二个问题:
对int类型数据类型运用位移运算符位移与乘以2除以2位移的区别
观察以下代码:
int c = 3;
int i =1;
while (i<40){
c *= 2;
System.out.println(c);
i++;
}
结果:
6 12 24 48 96 192 384 768 1536 3072 6144 12288 24576 49152 98304 196608 393216 786432 1572864 3145728 6291456 12582912 25165824 50331648 100663296 201326592 402653184 805306368 1610612736 -1073741824 -2147483648 0 0 0 0 0 0 0 0
可看出:
利用*2 /2进行位移,不是循环位移,移位超过长度之后会为0. 由此引出下一个问题:
第三个问题:
运用计算机计算时,什么情况下会归零化?
推测结论:类似十进制中与含有10因数的数字相乘类似,因为计算机是二进制计算,且储存位数固定,利用第二个问题所带出的结论,所以对int类型当乘数中累计计算有2^32乘数时,必然会归零化。
尝试证明:观察以下代码,因数为4是,预测累计乘16次会归零
int c = 3;
int i =1;
while (i<17){
c *= 4;
System.out.println(c);
i++;
}
结果:
12
48
192
768
3072
12288
49152
196608
786432
3145728
12582912
50331648
201326592
805306368
-1073741824
0
//预测正确
再次尝试证明:当因数是6时,32次会归零
int c = 3;
int i =1;
while (i<33){
c *= 6;
System.out.println(c);
i++;
}
结果:
18
108
648
3888
23328
139968
839808
5038848
30233088
181398528
1088391168
-2059587584
527376384
-1130708992
1805680640
-2050818048
579993600
-815005696
-595066880
724566016
52428800
314572800
1887436800
-1560281088
-771751936
-335544320
-2013265920
805306368
536870912
-1073741824
-2147483648
0
//预测正确
结论:
当与偶数进行乘数运算时,因为二进制计算机制的原因,当int型累计乘数中含有2^32时,数值归零. 由此可推广:当对long类型累计乘数中有2^64时,数值归零.
验证推广:
long c = 3;
long i =1;
while (i<65){
c *= 6;
System.out.println(c);
i++;
}
结果:
18
108
648
3888
23328
139968
839808
5038848
30233088
181398528
1088391168
6530347008
39182082048
235092492288
1410554953728
8463329722368
50779978334208
304679870005248
1828079220031488
10968475320188928
65810851921133568
394865111526801408
2369190669160808448
-4231600058744700928
-6942856278758653952
-4763649525132820480
8311590996622180352
-5470686241395572736
4069370699045666816
5969480120564449280
-1076607424032407552
-6459644544194445312
-1864379117747568640
7260469367224139776
6669328055925735424
3122480188135309312
288137055102304256
1728822330613825536
-8073810090026598400
6897371680969064448
4490741938395283456
8497707556662149120
-4353986881155760128
-7677177213225009152
-9169575131930951680
322781429542944768
1936688577257668608
-6826612610163539968
-4066187513562136576
-5950381007663267840
1191202101439496192
7147212608636977152
5989787504402759680
-954763121002545152
-5728578726015270912
2522015791327477760
-3314649325744685056
-1441151880758558720
-8646911284551352320
3458764513820540928
2305843009213693952
-4611686018427387904
-9223372036854775808
0