如何在Solidity中用移位操作实现非二进制数去零(替代除法)?
不用除法去除十进制末尾零:移位操作不可行,附替代实现
首先明确:没法单纯靠移位操作实现去除十进制数字末尾的零。原因很简单:移位是针对二进制位的操作(左移等价于乘2,右移等价于除以2),而十进制末尾的零意味着数字是10的倍数——也就是同时包含2和5的因子。移位只能处理2的幂次因子,但5不是2的幂,没有对应的移位操作能等价于除以5,所以单纯移位达不到需求。
举个实际例子:十进制的1000对应二进制是1111101000,如果直接右移3位(对应除以8),得到的结果是125,完全不是期望的10,这就直观说明了移位和十进制去零没有直接对应关系。
如果必须避开除法操作实现去零,可以结合移位、乘法逆元(针对5的因子)来实现,以下是Solidity代码示例:
function removeTrailingZeros(uint256 num) public pure returns (uint256) { if (num == 0) return 0; // 先移除所有2的因子:用右移替代除以2 while ((num & 1) == 0) { num >>= 1; } // 移除所有5的因子:用乘法逆元替代除以5(在2^256模空间下,5的逆元是固定值) uint256 inv5 = 0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc; while ((num % 5) == 0) { num = num * inv5; // 由于num是5的倍数,乘法结果等价于整数除法 } return num; }
如果连模运算也想避免,可以用循环减法判断数字是否能被5整除,但这种方式效率较低,仅适合小数值场景:
function removeTrailingZerosNoMod(uint256 num) public pure returns (uint256) { if (num == 0) return 0; // 移除2的因子 while ((num & 1) == 0) { num >>= 1; } // 移除5的因子:用循环减法判断是否能被5整除 while (true) { uint256 temp = num; bool divisibleBy5 = false; // 反复减5直到小于5,判断结果是否为0 while (temp >= 5) { temp -= 5; } if (temp != 0) break; // 用逆元除以5 uint256 inv5 = 0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc; num = num * inv5; } return num; }
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

