我为一,发现比较大数比小数更困难。
我想知道对于CPU是否相同。是否有任何硬件允许较小的数字比较大的数字被更快地划分。
例如
100 / (uint8_t) 255
100 / (char) 255
100 / (int) 255
100 / (int) 2147483647
100 / (long) 2147483647
100 / (long) 9223372036854775807
我可以想象除法过程需要更多的步骤才能得到更大的数字,因此需要ALU进行更多的说明。我不确定数据类型是否会对此产生任何影响?
这些数字的除法之间是否会有明显的区别? 如果有机会,用较小的数字进行除法通常会更好(这是任何形式的优化)吗?
答案 0 :(得分:0)
这取决于内部实现。考虑以下朴素的二进制长除法:
struct div_t{
int quot;
int rem;
};
struct div_t div(int dividend, int divisor){
_Bool dividend_is_negative = (dividend < 0),
divisor_is_negative = (divisor < 0),
result_is_negative = divisor_is_negative ^ dividend_is_negative;
unsigned quotient =0, shift, shifted;
//if (dividend_is_negative) dividend = -dividend;
divisor ^= -divisor_is_negative;
divisor += divisor_is_negative;
//if (dividend_is_negative) dividend = -dividend;
dividend ^= -dividend_is_negative;
dividend += dividend_is_negative;
shifted = divisor;
//shift divisor so its MSB is same as dividend's - minimize loops
//if no builtin clz, then shift divisor until its >= dividend
//such as: while (shifted<dividend) shifted<<=1;
shift = __builtin_clz(divisor)-__builtin_clz(dividend);
//clamp shift to 0 to avoid undefined behavior
shift &= -(shift > 0);
shifted<<=shift;
do{
unsigned tmp;
quotient <<=1;
tmp = (unsigned long) (shifted <= dividend);
quotient |= tmp;
//if (tmp) dividend -= shifted;
dividend -= shifted & -tmp;
shifted >>=1;
}while (shifted >= divisor);
//if (result_is_negative) quotient=-quotient, dividend=-dividend;
quotient ^= -result_is_negative;
dividend ^= -result_is_negative;
quotient += result_is_negative;
dividend += result_is_negative;
return (struct div_t){quotient, dividend};
}
显然,对于较小的数字,在天真的实现中循环会更快终止。
如果整个回路在电路中展开并并行化,则将占用大量芯片空间,因为每个位都依赖于较高位。对于台式机,服务器和超级计算机而言,这通常是值得的,但对于移动,嵌入式或物联网则不那么值得。
许多可配置的芯片组(risc-v,j-core等)具有快速划分和缓慢划分的选项,而有些则完全忽略了它们,让编译器执行类似我的示例的事情。