一次粗心引起的死循环



场景



一次系统升级中,需要修改一个需求,而这个需求需要修改一个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我们一起讨论~~


附加



由一个死循环引出的一系列问题及思考        

长按二维码关注我吧(微信公众号)

不要错过





相关文章:

  • 2021-11-07
  • 2021-07-31
  • 2021-12-12
  • 2021-11-24
  • 2022-12-23
  • 2022-01-02
  • 2022-12-23
  • 2021-05-11
猜你喜欢
  • 2022-02-22
  • 2022-01-19
  • 2021-08-23
  • 2022-01-31
  • 2022-12-23
  • 2022-12-23
  • 2021-09-29
相关资源
相似解决方案