我们可以使用位运算符从十进制转换到除4、8、16等以外的其他进制吗?我知道如何为4、8、16等等做这件事。但是从十进制到以3为基数,或者以12为基数,我就不知道了。有可能吗?
我想你的问题是在修正从二进制到其他基数的转换。
所有算术运算都可以简化为位运算和移位。这也是CPU在硬件内部所做的。
a + b ==> (a ^ b) + ((a & b) << 1)
右边仍然有一个+
在那里,所以你必须一次又一次地应用相同的变换,直到你的左移大于你的整数类型的宽度。或者一点一点地循环。
与两个补数:
-a ==> ~a + 1
如果有+
和negate
就有-
。*
只是一堆移位和添加。/
是一堆移位和减法。想想你在学校里是怎么做乘法和长除法的,然后把它降到以2为底。
对于大多数基数来说,用位运算进行数学运算是疯狂的。特别是如果您的代码是从上面的基本操作派生出来的。cpu的加法、子运算和多运算都很好,而且速度更快。但是,如果您想为独立环境(如内核)实现printf()
,则可能需要对uint64_t / 10
进行划分,这是CPU在硬件中无法完成的。编译器(gcc, clang)也不够聪明,不能很好地做到这一点,它退回到一般的迭代uint64_t / uint64_t
长除法算法。
但是除法可以通过乘以逆移几位并将结果移回来来完成。这个方法对于除以10的除法效果很好,你会得到很好的优化代码:
uint64_t divu10(uint64_t n) {
uint64_t q, r;
q = (n >> 1) + (n >> 2);
q = q + (q >> 4);
q = q + (q >> 8);
q = q + (q >> 16);
q = q + (q >> 32);
q = q >> 3;
r = n - (((q << 2) + q) << 1);
return q + (r > 9);
}
这比gcc/clang在编写x / 10
时调用的一般uint64_t / uint64_t
长除法函数更短,速度更快。
注:(((q << 2) + q) << 1)
为q * 10
。当cpu没有64位整数时,另一个比q * 10
更快的按位操作