由位移运算符所想到的三个有趣结论

 

此文章试图解答以下三个问题:

  • 对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

 推测正确.

 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值