C签名和unsigned int vs long long speed
今天,我注意到在我的64位PC上,int,unsigned,long long和unsigned long long之间的几个简单的按位和算术运算的速度差别很大.
特别是,对于unsigned而言,以下循环的速度大约是long long的两倍,这是我没想到的. int k = 15; int N = 30; int mask = (1 << k) - 1; while (!(mask & 1 << N)) { int lo = mask & ~(mask - 1); int lz = (mask + lo) & ~mask; mask |= lz; mask &= ~(lz - 1); mask |= (lz / lo / 2) - 1; } (完整代码here) 以下是时间(以秒为单位)(对于g -O,-O2和-O3): 1.834207723 (int) 3.054731598 (long long) 1.584846237 (unsigned) 2.201142018 (unsigned long long) 这些时间非常一致(即1%的保证金). 这有明显的原因吗? 对于那些感兴趣的人,这个循环遍历{1,2,…,30}的所有子集,恰好有15个元素.这是通过在小于1 <<<<<<<<<<<<<<<<<<<< 30> 编辑 从汇编代码看,当类型未签名时,可以使除法更快.我认为这是有道理的,因为我们不必考虑符号位. 此外,32位操作使用movl和其他xxxl指令, 编辑2 在阅读我链接的帖子后,我决定使用那里给出的公式: T k = 15; T N = 30; T mask = (1 << k) - 1; while (!(mask & 1 << N)) { T t = mask | (mask - 1); mask = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(mask) + 1)); } 这在上面发布的代码的大约三分之一的时间内运行,并且对所有四种类型使用相同的时间. 解决方法
代码中最慢的操作是
mask |= (lz / lo / 2) - 1 32位除法明显快于64位除法.例如,在Ivy Bridge上,32位IDIV需要19-26个时钟,而64位IDIV需要28-103个时钟延迟. 无符号版本也比签名更快,因为除以2是在无符号情况下的简单位移,并且没有大小扩展调用(CDQ,CQO). 在无符号的情况下,在签名时是简单的位移 [1] http://www.agner.org/optimize/instruction_tables.pdf (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |