与谜题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的移位操作符的语义正是许多处理器上的移位指令的语义。

转载于:https://www.cnblogs.com/yuyu666/p/9840436.html

谜题27:变幻莫测的i值相关推荐

  1. react学习(27)---antdesign设置默认值

    {getFieldDecorator('activityTimeStamp', {rules: [{ required: true, message: '请选择活动时间' }],initialValu ...

  2. Java解惑 电子书

    --表达式谜题 Java 谜题 1--表达式谜题 谜题 1:奇数性 下面的方法意图确定它那唯一的参数是否是一个奇数.这个方法能够正确运转 吗? public static boolean isOdd( ...

  3. python 如果没有该key值置为空_在python字典中用“None”替换空值

    我有一个从arcgis shapefile生成的Python字典.字典的key=FID(point ID):value=nothing或"HH".字典是这样的:Cluster_di ...

  4. 跟风写博---也谈值类型和引用类型

    在博客园潜水一年多,半年前开了博,但一直闲置着,前阵子看了老赵的博客二三事后,终于下了决定要认真写几篇.正巧最近园子在讨论"值类型和引用类型"相关的话题,我就谈谈个人见解. 直接从 ...

  5. go语言求时间的差值(按天数算)

    问题 开发时经常遇到求时间的差值,比如2019/05/05和2019/04/27日的差值是多少,相差多少天? time包 func GetTimeArr(start, end string) int6 ...

  6. c语言几行代码打印每个英文字符对应的码值(十进制表示形式)

    CharToIntValue.c 源码: #include <stdio.h> int main(){char c;int i;while(0<1){scanf("%c&q ...

  7. 暗幽***风恋组综合工具解压安装包2013元月27日更新版

    此版在前版的基础上再次增加了S版工具,也再次修改了工具包里的工具,力求奉献出一个精简完美高效的工具包,但因精力实在有限,所以依然难免存在缺陷,请大家海涵-     前版的工具包集合了:UnPacKcN ...

  8. java解惑你知道多少_Java解惑

    第1章 绪论 第2章 表达式之谜 谜题1:奇数性 谜题2:找零时刻 谜题3:长整除 谜题4:初级问题 谜题5:十六进制的趣事 谜题6:多重转型 谜题7:互换内容 谜题8:DOS EQUIS 谜题9:半 ...

  9. java---解惑--

    Java谜题1--表达式谜题 谜题1:奇数性 下面的方法意图确定它那唯一的参数是否是一个奇数.这个方法能够正确运转吗? public static boolean isOdd(int i){  ret ...

最新文章

  1. php json 数组 区别,PHP实战:JSON两种结构之对象和数组的理解
  2. CocoStudio资源区导入Plist/PSD文件
  3. win7冒险岛java,win7玩冒险岛不兼容怎么办?解决win7玩冒险岛不兼容的方法
  4. 主成分分析(PCA)和独立成分分析(ICA)相关资料
  5. 社区奖品之原木双面记事板
  6. 64位ubuntu16.04下pycharm无法切换fcitx输入法和无法输入中文的问题
  7. jquery实现饼图统计图表
  8. 【HTML/CSS】margin塌陷和合并问题
  9. 【转载】在.NET环境中实现每日构建--NAnt篇
  10. linux系统q7文件,linux系统安装包的管理
  11. 简易的文件上传 tp5
  12. 【阿里云视频点播加密视频播放报错】:网络错误加载数据失败(fragLoadError)或者403
  13. linux spdbv教程,计算机化学实践基础教程
  14. visio设置图片默认大小_visio怎么调整图片大小、间距-visio调整图片大小、间距的方法 - 河东软件园...
  15. 一般系统论--一些系统问题读书笔记
  16. centos7.6安装Kubernetes1.14.1集群
  17. orientdb java_OrientDB Java连接操作
  18. 第三十三章 SQL函数 COT
  19. 现代的linux和windows7,Windows 7 Vs. Linux谁更强
  20. 三分钟搭建开源的工单系统ferry

热门文章

  1. 树莓派 ubuntu gpio_树莓派学习笔记(一)输入输出GPIO
  2. python打包和添加数据文件_Python打包时添加非代码文件的坑
  3. c++ websocket客户端_WebSocket协议详解与c++amp;c#实现
  4. RedisTemplate清空所有键值对
  5. redis允许其他机器远程连接
  6. Ubuntu18.04安装Docker并构建JDK1.8镜像
  7. 定积分在计算机中的应用,计算机模拟定积分的定义
  8. cron计划任务、chkconfig工具、systemd管理服务、unit、target介绍
  9. Linux 下的驱动开发最简单例子
  10. Show ip arp 和 Show mac-address-table