谜题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的老 ...
随机推荐
- linux kernel 关于RSS/RPS/RFS/XPS的介绍
Introduction============ This document describes a set of complementary techniques in the Linuxnetwo ...
- [Leetcode] add binary 二进制加法
Given two binary strings, return their sum (also a binary string). For example,a ="11"b =& ...
- 【BZOJ 1492】 [NOI2007]货币兑换Cash 斜率优化DP
先说一下斜率优化:这是一种经典的dp优化,是OI中利用数形结合的思想解决问题的典范,通常用于优化dp,有时候其他的一些决策优化也会用到,看待他的角度一般有两种,但均将决策看为二维坐标系上的点,并转化为 ...
- 【BZOJ 1930】 [Shoi2003]pacman 吃豆豆 最大费用最大流
如果你知道他是网络流的话你就很快会想到一个最大费用最大流的模型,然后你发现可能T,然而你发现你只用增广两次,然后你就开心的打了出来,然后发现被稠密图里spfa的丧病时间复杂度坑了,还是会T.于是我就开 ...
- Codeforces Round #350 (Div. 2) D1
D1. Magic Powder - 1 time limit per test 1 second memory limit per test 256 megabytes input standard ...
- Tile Cut~网络流入门题
Description When Frodo, Sam, Merry, and Pippin are at the Green Dragon Inn drinking ale, they like t ...
- Django随笔 01
Django 视图 不处理用户输入,而仅仅决定要展现哪些数据给用户: Django 模板 仅仅决定如何展现Django视图指定的数据. dd http://blog.csdn.net/pipisorr ...
- HTML5 视频直播
目前视频直播,尤其是移动端的视频直播已经火到不行了,基本上各大互联网公司都有了自己的直播产品,所以对于直播的一些基本知识和主要技术点也要有所了解,本次分享就向大家介绍一下其中的奥秘. 内容大体框架: ...
- mavne问题解决---Dynamic Web Module 2.3 or newer
一:前沿 maven问题的bug,其实是很烦人的,因为每次都是很纠结的去改这个bug,特别的烦人,这个bug也是使得我纠结了好久的,那个星期五自己搞了几个小时都没有解决下,之后星期一来百度Google ...
- Spring MVC框架下 将数据库内容前台页面显示完整版【获取数据库人员参与的事件列表】
1.书写jsp页面包括要显示的内容[people.jsp] <!-- 此处包括三个方面内容: 1.包含 文本输入框 查询按钮 查询结果显示位置 (paging) 2.包括对按钮(button) ...