如何在不使用任何比较运算符且不使用 , 等的情况下以编程方式返回两个整数的if
最大值else
?
12 回答
max: // 将 MAX(a,b) 放入 a
a -= b;
a &= (~a) >> 31;
a += b;
和:
整数a,b;
min: // 将 MIN(a,b) 放入 a
a -= b;
a &= a >> 31;
a += b;
从这里。
http://www.graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
r = x - ((x - y) & -(x < y)); // max(x, y)
您可以通过算术移位(x - y)
使符号位饱和来获得乐趣,但这通常就足够了。或者你可以测试高位,总是很有趣。
在数学世界中:
max(a+b) = ( (a+b) + |(a-b)| ) / 2
min(a-b) = ( (a+b) - |(a-b)| ) / 2
除了在数学上正确之外,它并没有像移位操作那样对位大小做出假设。
|x|
代表 x 的绝对值。
评论:
你是对的,绝对值被遗忘了。这应该对所有 a、b 正面或负面都有效
我想我明白了。
int data[2] = {a,b};
int c = a - b;
return data[(int)((c & 0x80000000) >> 31)];
这行不通吗?基本上,你取两者的差,然后根据符号位返回一个或另一个。(这就是处理器大于或小于的方式。)因此,如果符号位为 0,则返回 a,因为 a 大于或等于 b。如果符号位为 1,则返回 b,因为 a 减去 b 导致结果为负,表示 b 大于 a。只需确保您的整数是 32 位签名的。
返回 (a > b ? a : b);
或者
int max(int a, int b)
{
int x = (a - b) >> 31;
int y = ~x;
return (y & a) | (x & b);
}
从 z0mbie(著名的 virii 作家)的文章“多态游戏”中,也许你会发现它很有用:
#define H0(x) (((signed)(x)) >> (sizeof((signed)(x))*8-1))
#define H1(a,b) H0((a)-(b))
#define MIN1(a,b) ((a)+(H1(b,a) & ((b)-(a))))
#define MIN2(a,b) ((a)-(H1(b,a) & ((a)-(b))))
#define MIN3(a,b) ((b)-(H1(a,b) & ((b)-(a))))
#define MIN4(a,b) ((b)+(H1(a,b) & ((a)-(b))))
//#define MIN5(a,b) ((a)<(b)?(a):(b))
//#define MIN6(a,b) ((a)>(b)?(b):(a))
//#define MIN7(a,b) ((b)>(a)?(a):(b))
//#define MIN8(a,b) ((b)<(a)?(b):(a))
#define MAX1(a,b) ((a)+(H1(a,b) & ((b)-(a))))
#define MAX2(a,b) ((a)-(H1(a,b) & ((a)-(b))))
#define MAX3(a,b) ((b)-(H1(b,a) & ((b)-(a))))
#define MAX4(a,b) ((b)+(H1(b,a) & ((a)-(b))))
//#define MAX5(a,b) ((a)<(b)?(b):(a))
//#define MAX6(a,b) ((a)>(b)?(a):(b))
//#define MAX7(a,b) ((b)>(a)?(b):(a))
//#define MAX8(a,b) ((b)<(a)?(a):(b))
#define ABS1(a) (((a)^H0(a))-H0(a))
//#define ABS2(a) ((a)>0?(a):-(a))
//#define ABS3(a) ((a)>=0?(a):-(a))
//#define ABS4(a) ((a)<0?-(a):(a))
//#define ABS5(a) ((a)<=0?-(a):(a))
干杯
不像上面的那么时髦……但是……
int getMax(int a, int b)
{
for(int i=0; (i<a) || (i<b); i++) { }
return i;
}
由于这是一个谜题,解决方案会稍微复杂:
let greater x y = signum (1+signum (x-y))
let max a b = (greater a b)*a + (greater b a)*b
这是 Haskell,但在任何其他语言中都是一样的。C/C# 的人应该使用“sgn”(或“sign”?)而不是 signum。
请注意,这将适用于任意大小的整数和实数。
这是一种欺骗,使用汇编语言,但它仍然很有趣:
// GCC inline assembly
int max(int a, int b)
{
__asm__("movl %0, %%eax\n\t" // %eax = a
"cmpl %%eax, %1\n\t" // compare a to b
"cmovg %1, %%eax" // %eax = b if b>a
:: "r"(a), "r"(b));
}
如果您想严格遵守规则并说该cmpl
指令对此是非法的,那么以下(效率较低的)序列将起作用:
int max(int a, int b)
{
__asm__("movl %0, %%eax\n\t"
"subl %1, %%eax\n\t"
"cmovge %0, %%eax\n\t"
"cmovl %1, %%eax"
:: "r"(a), "r"(b)
:"%eax");
}
这些函数使用比较但不进行测试,并且在符合标准的系统上完全定义:
int min(int a, int b) {
return (a <= b) * a + (b < a) * b;
}
int max(int a, int b) {
return (a <= b) * b + (b < a) * a;
}
这是一个没有乘法的替代方案,可移植到使用二进制补码作为负数的系统:
int min(int a, int b) {
return (a & -(a <= b)) | (b & -(b < a));
}
int max(int a, int b) {
return (b & -(a <= b)) | (a & -(b < a));
}
两个版本都适用于所有整数类型。
请注意,gcc和clang都为上述函数生成无分支代码,并且clang为这两种替代方案生成了相同的最佳代码,这可以在此Godbolt Compiler Explorer session中看到。
这是我在 C# 上仅使用+, -, *, %, /
运算符的实现
using static System.Console;
int Max(int a, int b) => (a + b + Abs(a - b)) / 2;
int Abs(int x) => x * ((2 * x + 1) % 2);
WriteLine(Max(-100, -2) == -2); // true
WriteLine(Max(2, -100) == 2); // true
int max(int a, int b)
{
return ((a - b) >> 31) ? b : a;
}