C 中 6 次运算中的带符号饱和乘以 2?

Min*_*int 6 c bit-manipulation bitwise-operators micro-optimization saturation-arithmetic

有符号 2 的补码 32 位整数的问题:

\n
\n

satMul2- 乘以 2,饱和TminTmax溢出。
\n示例: satMul2(0x30000000) = 0x60000000
\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 satMul2(0x40000000) = 0x7FFFFFFF(饱和到TMax)
\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 satMul2(0x60000000) = 0x80000000(饱和到TMin)
\n合法操作:! ~ & ^ | + << >>
\n最大操作:20
\n评级:3

\n
\n

我想实现一个类似的功能

\n
if (a) return b;\nelse return c;\n
Run Code Online (Sandbox Code Playgroud)\n

这是我的解决方案(10 次操作):

\n
int satMul2(int x) {\n    int rval = x << 1;\n    int sign = rval ^ x;\n    int minn = 1 << 31;\n    int temp = sign >> 31;\n    int flow = minn ^ (rval >> 31);\n    return ((~temp) & rval) | (temp & flow);    \n}\n
Run Code Online (Sandbox Code Playgroud)\n

我的教授告诉我有一个只需 6 次操作的解决方案。有人可以给我一些提示吗?

\n

chq*_*lie 5

您的解决方案有 2 个未定义行为的实例(一种是潜在的,一种是显式的),还有 2 个显式实现定义的行为。最好建议您的教授教授这些内容,而不是沉迷于诸如最小化操作之类的虚假挑战。

这是一个正确的可移植实现:

#include <limits.h>

int satMul2(int x) {
    return x > INT_MAX / 2 ? INT_MAX :
           x < INT_MIN / 2 ? INT_MIN : x * 2;
}
Run Code Online (Sandbox Code Playgroud)

正如可以使用Godbolt 的编译器资源管理器进行研究的那样,clang将此函数编译为高效的无分支代码:

#include <limits.h>

int satMul2(int x) {
    return x > INT_MAX / 2 ? INT_MAX :
           x < INT_MIN / 2 ? INT_MIN : x * 2;
}
Run Code Online (Sandbox Code Playgroud)