谜题27:变幻莫测的i值
与谜题26中的程序一样,下面的程序也包含了一个记录在终止前有多少次迭代的循环。与那个程序不同的是,这个程序使用的是左移操作符(<<)。你的任务照旧是要指出这个程序将打印什么。当你阅读这个程序时,请记住 Java 使用的是基于2的补码的二进制算术运算,因此-1在任何有符号的整数类型中(byte、short、int或long)的表示都是所有的位被置位:
public class Shifty {
public static void main(String[] args) {
int i = 0;
while (-1 << i != 0)
i++;
System.out.println(i);
}
}
常量-1是所有32位都被置位的int数值(0xffffffff)。左移操作符将0移入到由移位所空出的右边的最低位,因此表达式(-1 << i)将i最右边的位设置为0,并保持其余的32 - i位为1。很明显,这个循环将完成32次迭代,因为-1 << i对任何小于32的i来说都不等于0。你可能期望终止条件测试在i等于32时返回false,从而使程序打印32,但是它打印的并不是32。实际上,它不会打印任何东西,而是进入了一个无限循环。
问题在于(-1 << 32)等于-1而不是0,因为移位操作符之使用其右操作数的低5位作为移位长度。或者是低6位,如果其左操作数是一个long类数值[JLS 15.19]。
这条规则作用于全部的三个移位操作符:<<、>>和>>>。移位长度总是介于0到31之间,如果左操作数是long类型的,则介于0到63之间。这个长度是对32取余的,如果左操作数是long类型的,则对64取余。如果试图对一个int数值移位32位,或者是对一个long数值移位64位,都只能返回这个数值自身的值。没有任何移位长度可以让一个int数值丢弃其所有的32位,或者是让一个long数值丢弃其所有的64位。
幸运的是,有一个非常容易的方式能够订正该问题。我们不是让-1重复地移位不同的移位长度,而是将前一次移位操作的结果保存起来,并且让它在每一次迭代时都向左再移1位。下面这个版本的程序就可以打印出我们所期望的32:
public class Shifty {
public static void main(String[] args) {
int distance = 0;
for (int val = -1; val != 0; val <<= 1)
distance++;
System.out.println(distance);
}
}
这个订正过的程序说明了一条普遍的原则:如果可能的话,移位长度应该是常量。如果移位长度紧盯着你不放,那么你让其值超过31,或者如果左操作数是long类型的,让其值超过63的可能性就会大大降低。当然,你并不可能总是可以使用常量的移位长度。当你必须使用一个非常量的移位长度时,请确保你的程序可以应付这种容易产生问题的情况,或者压根就不会碰到这种情况。
前面提到的移位操作符的行为还有另外一个令人震惊的结果。很多程序员都希望具有负的移位长度的右移操作符可以起到左移操作符的作用,反之亦然。但是情况并非如此。右移操作符总是起到右移的作用,而左移操作符也总是起到左移的作用。负的移位长度通过只保留低5位而剔除其他位的方式被转换成了正的移位长度——如果左操作数是long类型的,则保留低6位。因此,如果要将一个int数值左移,其移位长度为-1,那么移位的效果是它被左移了31位。
总之,移位长度是对32取余的,或者如果左操作数是long类型的,则对64取余。因此,使用任何移位操作符和移位长度,都不可能将一个数值的所有位全部移走。同时,我们也不可能用右移操作符来执行左移操作,反之亦然。如果可能的话,请使用常量的移位长度,如果移位长度不能设为常量,那么就要千万当心。
语言设计者可能应该考虑将移位长度限制在从0到以位为单位的类型尺寸的范围内,并且修改移位长度为类型尺寸时的语义,让其返回0。尽管这可以避免在本谜题中所展示的混乱情况,但是它可能会带来负面的执行结果,因为Java的移位操作符的语义正是许多处理器上的移位指令的语义。
谜题27:变幻莫测的i值的更多相关文章
- JAVA中计算两个日期时间的差值竟然也有这么多门道
上半年春招的时候,作为面试官,对于面试表现的不错的同学会要求其写一小段代码看看.题目很简单: 给定一个日期,然后计算下距离今天相差的天数. 本以为这么个问题就是用来活跃面试氛围的,但是结果却让人大跌眼 ...
- Java常见问题3:周期之谜
谜24 byte是有符号的.范围是-128 - 127. 而0x90是int类型. 比較的时候.不相等. 假设想让其相等,须要进行类型转换:(byte & 0xff) 或者 (byte)0x9 ...
- 分布式系统理论进阶 - Paxos
引言 <分布式系统理论基础 - 一致性.2PC和3PC>一文介绍了一致性.达成一致性需要面临的各种问题以及2PC.3PC模型,Paxos协议在节点宕机恢复.消息无序或丢失.网络分化的场景下 ...
- Python 【第六章】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...
- Java使用Fork/Join框架来并行执行任务
现代的计算机已经向多CPU方向发展,即使是普通的PC,甚至现在的智能手机.多核处理器已被广泛应用.在未来,处理器的核心数将会发展的越来越多. 虽然硬件上的多核CPU已经十分成熟,但是很多应用程序并未这 ...
- python走起之第十一话
Redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...
- JVM之数据类型
1.概述 Java虚拟机的数据类型可分为两大类:原始类型(Primitive Types,也称为基本类型)和引用类型(Reference Types).Java虚拟机用不同的字节码指令来操作不同的数据 ...
- Memcached & Redis使用
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached ...
- 基于SPSS的美国老年夏季运动会运动员数据分析
本文是课程训练的报告,部分图片由于格式原因并没有贴出,有兴趣者阅读完整报告者输入以下链接 http://files.cnblogs.com/files/liugl7/基于SPSS的老 ...
随机推荐
- POJ3623 Best Cow Line, Gold 【后缀数组】
最好的牛线,金 时间限制: 5000MS 内存限制: 65536K 提交总数: 5917 接受: 2048 描述 FJ即将把他的ñ(1≤ ñ ≤30,000)头牛竞争一年一度的"年度 ...
- 【NOIP模拟赛】就 反悔贪心
biubiu~~~ 这道题,考场上上来就dp然后发现怎么优化也不行.............最后发现是贪心............. 正解:带反悔的贪心,原理是,假设我们现在得到了取i个的最优解那么我 ...
- [COGS 2421] [HZOI 2016] 简单的Treap 笛卡尔树
笛卡尔树就是你给两维限制,一维堆R,一维二叉搜索树K,平地拔起一棵Treap,最广范的应用:用LCA求区间最值,建Treap,还有个什么范围top k我表示并不会查都查不到.它最妙最高的地方在于用栈来 ...
- 论文笔记《Spatial Memory for Context Reasoning in Object Detection》
好久不写论文笔记了,不是没看,而是很少看到好的或者说值得记的了,今天被xinlei这篇paper炸了出来,这篇被据老大说xinlei自称idea of the year,所以看的时候还是很认真的,然后 ...
- POJ2594:Treasure Exploration(Floyd + 最小路径覆盖)
Treasure Exploration Time Limit: 6000MS Memory Limit: 65536K Total Submissions: 9794 Accepted: 3 ...
- windows远程桌面访问ubuntu12.04
转载自 : http://blog.csdn.net/shuzui1985/article/details/7592569 1.dashboard----桌面共享 我们共享所使用的协议是rdp,所以我 ...
- SpringMVC学习 -- IDEA 创建 HelloWorld
SpringMVC 概述: Spring 为展现层提供的基于 MVC 实际理念的优秀 Web 框架 , 是目前最主流的 MVC 框架之一. 自 Spring3.0 发布及 2013 年 Struts ...
- Sencha Touch MVC 中 store 的使用
I have a UserStore that I want to load after succesful login of a user. I can't get this to work i.e ...
- AtCoder Regular Contest 075 D Widespread
题目传送门 这道题其实二分一下答案就okay了的 不过LL什么的有时候忘了加 被卡了下 #include<cstdio> #include<cstring> #include& ...
- 【BZOJ】[SDOI2009]HH的项链
[算法]主席树||离线+树状数组 [题解] 主席树经典应用:找区间不同的数字个数. 做法:记录每个数上一次出现的位置last[i],对last建权值线段树,对于区间询问last[i]<L的数字个 ...