如果你学过数制转换,一定记得那个“乘2取整法”:不断将小数部分乘以2,记录整数位,直到小数部分为零。这个方法应对考试足够了,但它的运作原理却像个魔术——依步骤而行,答案正确,你却说不清为何有效,也猜不透为何有时会无限循环。
以0.25为例。标准流程是:0.25×2=0.50,记录0;0.50×2=1.00,记录1;自上而下读,二进制表示为0.01。答案没错,却失于机械。另一种思路是:0.25就是1/4,而4是2²。那何不把分子和分母分别转为二进制,再完成这次除法?
分子1在二进制中仍是1,分母4转为二进制是100。于是1/4就成了二进制中的1/100。除以100(以2为底的100,即十进制4)不需要长除法,因为100正是基数的幂次——正如十进制里除以100相当于移动两位小数点。二进制中,除以100₂同样让二进制小数点左移两位:把“1.”移位后得0.01₂。输出结果与乘2法一致,但这次你清楚看见了背后的位置逻辑。
这并非巧合,而是位值系统的通理。任何形如a/2ⁿ的分数,都可以把a写成二进制,再移动n位小数点。1/2位移1位得0.1₂,1/8位移3位得0.001₂,3/16(3写作11₂)移4位得0.0011₂。这说明为何在嵌入式系统的定点数算术中,程序员常把分数隐含地当作整数加一个二进制小数点来处理,让位位移取代除法——这个“技巧”实则是定点数思想的手动版。
捷径依赖一个硬条件:分母必须是2的整数次幂。换成0.2,也就是分数1/5,就完全行不通了。5在二进制中是101——它是4+1,而非单一的2的幂次,无从施展干净的移位。要计算1/101₂,必须回归二进制长除法,而且这个除法不会终结,会得到无限循环的0.0011001100110011…₂。同样的结构性问题,也解释了为何大多数编程语言中0.1加0.2不恰好等于0.3:那些小数在二进制里无法被精确截断,截断就会带来舍入误差。
热门跟贴