【发布时间】:2017-10-19 12:23:18
【问题描述】:
所以,我们都知道 -1 > 2u == true 的 C/C++ 有符号/无符号比较规则,我有一种情况,我想有效地实现“正确”比较。
我的问题是,考虑到人们熟悉的尽可能多的架构,哪种方法更有效。显然英特尔和 ARM 的权重更高。
给定:
int x;
unsigned int y;
if (x < y) {}
推广是不是更好:
x < y => (int64)x < (int64)y
或者执行2个比较更好,即:
x < y => (x < 0 || x < y)
前者意味着零扩展、符号扩展和一个比较+分支,后者不需要符号扩展操作,但需要 2 个连续的 cmp+分支。
传统观点认为分支比符号扩展更昂贵,这两者都会流水线,但在第一种情况下,扩展和单一比较之间存在停顿,而在第二种情况下,我可以想象某些架构可能会流水线化 2 个比较,但随后是2个条件分支?
存在另一种情况,无符号值是比有符号类型更小的类型,这意味着可以通过对有符号类型的长度进行一次零扩展,然后进行一次比较......在这种情况下,是使用extend+cmp 版本更可取,还是仍然首选2-comparison 方法?
英特尔?手臂?其他的? 我不确定这里是否有正确的答案,但我想听听人们的看法。如今,低级性能很难预测,尤其是在 Intel 上,在 ARM 上也越来越多。
编辑:
我应该补充一下,有一个明显的解决方案,其中类型的大小等于架构的 int 宽度;在这种情况下,显然首选 2 比较解决方案,因为促销本身不能有效地执行。显然,我的int 示例满足了 32 位架构的这个条件,您可以将思想实验转换为 short 以进行应用于 32 位平台的练习。
编辑 2:
抱歉,我忘记了-1 > 2u 中的u! >_
编辑 3:
我想修改这种情况,假设比较的结果是一个实际的分支,并且结果不是作为布尔值返回的。这就是我更喜欢结构外观的方式;尽管这确实提出了一个有趣的观点,即当结果是布尔值与分支时,还有另一组排列。
int g;
void fun(int x, unsigned in y) { if((long long)x < (long long)y) g = 10; }
void gun(int x, unsigned in y) { if(x < 0 || x < y) g = 10; }
当您遇到 if 时,这会产生通常暗示的预期分支;)
【问题讨论】:
-
评论不用于扩展讨论;这个对话是moved to chat。
标签: c++ c assembly type-conversion micro-optimization