由一个死循环引出的一系列问题及思考
2018-02-05 16:45
351 查看
一次粗心引起的死循环
场景
一次系统升级中,需要修改一个需求,而这个需求需要修改一个for循环的次数,原循环如下:
而修改后如下:
老司机很轻易的就能知道哪儿有问题,但是因为我的粗心,导致当时没有发现这个问题,造成了死循环,不过还好改的地方不多,几分钟就找到了这个地方。
问题原因
第二个为什么是死循环呢?这与java中数据类型的存储有关,byte类型的数值最多8位(二进制位),也就是byte的最大值也就是2^8 = 256了,有的同学可能会说,不对啊,java中byte不是-128~127吗,是的因为java中的number类型都是有符号的,所以符号位要占一位,也就是说java中的byte除去符号位其实也就7位,所以byte值也就是-128~127了,所以这个循环是永远不可能满足退出条件i
< 300的,因此造成了死循环。
再来说开篇的问题,第一个for循环退出条件是i < 30,这个是没问题的,但是修改的时候没有看i的类型,直接将for循环的退出条件修改为了i < 300,i的最大值也就127了自然是不会大于300了,所以修改后这个for循环就成为了一个死循环。
扩展
可能有的同学会问,既然byte类型的最大值是127,那么byte类型的127加1后是多少?这个其实可以自己把二进制写出来然后加一下答案就有了
127的二进制表示:
0111 1111
加1后的二进制表示:
1000 0000
因为最高位是符号位,所以可以知道该数值是一个负数,而对于一些同学可能知道以下概念:
原码
原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。例如:八位的情况下
+1表示为:
0000 0001
-1表示为:
1000 0001
看到这里,可能这部分同学想说,那上边的结果不就是-0了吗?但实际上并不是的,因为在计算机中实际对于负数并不是用的原码表示法,而是用的二补数(补码)。
首先我们需要了解以下概念:
补码
正整数的补码是其二进制表示,与原码相同,求负整数的补码,将其对应正数二进制表示所有位取反(包括符号位,0变1,1变0)后加1
有了以上概念就好算了,首先1000 0000最高位符号位是1,说明该值是一个负数,根据负数表示法逆推,想要得到正数需要先将该值减1,也就是:
1000 0000 - 1 = 0111 1111
然后将该值取反得到1000 0000
看到这里有的同学会问了,这不是跟没算一样吗?是的对于八位数来说1000 0000是个比较特殊的数字,他的补码还是他自己,但是你要仔细看概念,这样求得的数字是一个正数(求负数补码是在正数基础上求得的),也就是此时最高位的1就不用当符号位看了,所以对应的正数是128,加上原符号位也就是-128了。
同时也能发现,对于二补数来说是不存在-0的,因为任何一个非0二进制取反加1都不可能等于0(有兴趣的可以想一下为什么,很简单)。
至于为什么计算机采用二补数而不是原码表示法,可以自己思考一下,或者查询资料,或者加我的QQ群339634085我们一起讨论~~
附加
长按二维码关注我吧(微信公众号)
不要错过
场景
一次系统升级中,需要修改一个需求,而这个需求需要修改一个for循环的次数,原循环如下:
for(byte i = 0 ; i < 30 ; i++){ //do something }
而修改后如下:
for(byte i = 0 ; i < 300 ; i++){ //do something }
老司机很轻易的就能知道哪儿有问题,但是因为我的粗心,导致当时没有发现这个问题,造成了死循环,不过还好改的地方不多,几分钟就找到了这个地方。
问题原因
第二个为什么是死循环呢?这与java中数据类型的存储有关,byte类型的数值最多8位(二进制位),也就是byte的最大值也就是2^8 = 256了,有的同学可能会说,不对啊,java中byte不是-128~127吗,是的因为java中的number类型都是有符号的,所以符号位要占一位,也就是说java中的byte除去符号位其实也就7位,所以byte值也就是-128~127了,所以这个循环是永远不可能满足退出条件i
< 300的,因此造成了死循环。
再来说开篇的问题,第一个for循环退出条件是i < 30,这个是没问题的,但是修改的时候没有看i的类型,直接将for循环的退出条件修改为了i < 300,i的最大值也就127了自然是不会大于300了,所以修改后这个for循环就成为了一个死循环。
扩展
可能有的同学会问,既然byte类型的最大值是127,那么byte类型的127加1后是多少?这个其实可以自己把二进制写出来然后加一下答案就有了
127的二进制表示:
0111 1111
加1后的二进制表示:
1000 0000
因为最高位是符号位,所以可以知道该数值是一个负数,而对于一些同学可能知道以下概念:
原码
原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。例如:八位的情况下
+1表示为:
0000 0001
-1表示为:
1000 0001
看到这里,可能这部分同学想说,那上边的结果不就是-0了吗?但实际上并不是的,因为在计算机中实际对于负数并不是用的原码表示法,而是用的二补数(补码)。
首先我们需要了解以下概念:
补码
正整数的补码是其二进制表示,与原码相同,求负整数的补码,将其对应正数二进制表示所有位取反(包括符号位,0变1,1变0)后加1
有了以上概念就好算了,首先1000 0000最高位符号位是1,说明该值是一个负数,根据负数表示法逆推,想要得到正数需要先将该值减1,也就是:
1000 0000 - 1 = 0111 1111
然后将该值取反得到1000 0000
看到这里有的同学会问了,这不是跟没算一样吗?是的对于八位数来说1000 0000是个比较特殊的数字,他的补码还是他自己,但是你要仔细看概念,这样求得的数字是一个正数(求负数补码是在正数基础上求得的),也就是此时最高位的1就不用当符号位看了,所以对应的正数是128,加上原符号位也就是-128了。
同时也能发现,对于二补数来说是不存在-0的,因为任何一个非0二进制取反加1都不可能等于0(有兴趣的可以想一下为什么,很简单)。
至于为什么计算机采用二补数而不是原码表示法,可以自己思考一下,或者查询资料,或者加我的QQ群339634085我们一起讨论~~
附加
长按二维码关注我吧(微信公众号)
不要错过
相关文章推荐
- 一个C笔试题引出一系列的问题
- 一个小问题引出的有关CSS优先级的思考
- 一个detect问题引发的一系列思考
- 一个C笔试题引出一系列的问题
- 深入图解虚拟机(一)--一个问题引出的思考
- 透过现象看本质,一个Java多线程问题引出的思考
- 由一个RABBITMQ监听器死循环引出的SPRING中BEAN和MAPPER接口的注入问题
- 连号区间数 小明这些天一直在思考这样一个奇怪而有趣的问题:
- redis的一个set问题的思考
- 由一个#符号引发的一系列问题[转载]
- JCaptcha做验证码遇到的问题引出的思考
- 由一个属性设置导致的一系列问题排查
- 从错误信息思考一个问题:.NET Framework 与 COM/COM+ 到底有多深入的关联呢?
- 键盘、游戏、ASCII码引出的一系列问题
- 一个“粘贴”问题引发的思考
- 关于SQL组合查询问题的一个思考
- 一个循环解决下拉列表默认选择项问题
- 今天学习时突然联想到这样一个有趣但无用的问题:利用C语言(不能是其他语言)求两个整数的较大/小值-----要求不用if、三目?、switch、循环、数组、加减乘除求余、位运算符以及任何库函数
- 关于百度MP3问题引出的思考.....
- 解决VC6和VC2008的for循环变量作用域不同问题的一个方法