![每个人的Python:数学、算法和游戏编程训练营](https://wfqqreader-1252317822.image.myqcloud.com/cover/137/44510137/b_44510137.jpg)
上QQ阅读APP看书,第一时间看更新
4.5.1 编程实现——整数转换
![](https://epubservercos.yuewen.com/33C5B1/23721678209556606/epubprivate/OEBPS/Images/Figure-P92_15612.jpg?sign=1739254243-1mjWmP6Ef53IBNQPRLeTwWKtvE4EBr3d-0-fc503f68c52c984dd3d5e0b51b042f59)
输入两个整数A和B,尝试编写一个函数,计算最少需要改变多少位,才能将数字A转换成数字B,数字A和数字B都是32位的整数,可以是负数。
本题的核心是计算两个整数在内存中存储的二进制数据的差异位的个数。借助位运算,本题本身比较简单,然而如果使用Python语言来解决本题,还是存在一个陷阱,需要注意。
前面的章节介绍过,在Python中,数值都是以补码的形式存放在内存中的,对于正数来说,补码就是其二进制原码,对于负数来说,补码是其二进制原码的反码再加1。正数和负数的差别在于最高位的符号位不同,正数的符号位为0,负数的符号位为1。首先,如果按照正常的思路解决本题,通过异或运算统计两个二进制数不同的位的个数,对于都是正数的情况是没有问题的,示例代码如下:
![](https://epubservercos.yuewen.com/33C5B1/23721678209556606/epubprivate/OEBPS/Images/Figure-T93_29494.jpg?sign=1739254243-Oo1cjsSety8Kgu5KhaRuD9mlIKzYq6wf-0-b434f6b71b70f307e35a01ddc74d6003)
然而,如果输入的数A或B中存在负数,则上面的程序就不能正确工作了,假设输入A =1、B = ‒1,它们在内存中存储的32位二进制数据分别是:
![](https://epubservercos.yuewen.com/33C5B1/23721678209556606/epubprivate/OEBPS/Images/Figure-T93_29496.jpg?sign=1739254243-cfWxd8BisuiiOTVAeqcL5quZnd16FcMO-0-7ce1072f19bab750e4d90f21f16a507f)
根据题目的要求,这种场景的正确答案应该是需要改变31位才能将A转换成B,但是由于bin函数的缺陷,其会将负数直接输出为正数的二进制形式,并在最前面加上符号,因此上面的程序在执行时,异或运算首先得到的二进制数为:
![](https://epubservercos.yuewen.com/33C5B1/23721678209556606/epubprivate/OEBPS/Images/Figure-T93_29498.jpg?sign=1739254243-mUrYmGfd9iFdvRXJgzRIp6G688HS5Xc7-0-aefa5e1b3a436e233e9cdb1a9561ff4f)
bin函数执行后,会将其转换成:
![](https://epubservercos.yuewen.com/33C5B1/23721678209556606/epubprivate/OEBPS/Images/Figure-T93_29500.jpg?sign=1739254243-NWffA38boMONOI7RvgTybTScjxBYkkza-0-b370b6051eabbd2a567d9215e50c16f0)
最终统计1的结果将得到错误的答案1。在Python中,有一种方式可以非常巧妙地让bin函数输出二进制数值的补码形式,只要让原数与0xffffffff进行与运算即可。也可以这样理解,整数与0xffffffff进行与运算得到的数与原数相同,负数与0xffffffff进行与运算得到的是其补码对应的无符号整数。
要完美地解决本题,需要修改上面的代码如下:
![](https://epubservercos.yuewen.com/33C5B1/23721678209556606/epubprivate/OEBPS/Images/Figure-T93_29502.jpg?sign=1739254243-pnhbsTdTbhznfDuZOtrnS0sIrayiBOFh-0-ce15b51c0519f21309f9ed152f472311)