查看“bit-twiddling hacks”页面并研究如何实现最大值/最小值。
如果你能弄清楚两个数字的最大值是如何工作的,那么你就可以概括三个数字的情况。
让我给你解释一下获得最大值的两个数字的情况:
-(a<b) 可以返回 -1 或 0,然后您可以使用 11111111 11111111 11111111 11111111(整数补码中的 -1)或 00000000 00000000 00000000 00000000(整数 -0 == 0)。
记住a^b^b = a 和a^b^a = b(不管顺序是什么,这是xor 操作),在第一种情况下你就有了:
a ^ ((a ^ b) & -(a < b)) 必须等于a ^ a ^ b.. 事实上这是因为-(a<b) 返回11111111 11111111 11111111 11111111,并且对无符号整数的11111111 11111111 11111111 11111111 进行按位与& 运算使数字保持不变。 . 因此a ^ a ^ b = b。这是最大值。
- 如果
a > b 则a < b 为假,因此(anything & 00000000 00000000 00000000 00000000) 为0。因此您有a ^ 0,即a。最大值。
最后,我们将解决方案推广到三个数字:
#include <stdio.h>
int getMax(unsigned int a, unsigned int b, unsigned int c) {
int temp = a ^ ((a ^ b) & -(a < b)) ;
int r = c ^ ((c ^ temp) & -(c < temp));
return r;
}
int main(void) {
unsigned int a = 3, b = 1, c = 9;
printf("%d", getMax(a,b,c));
return 0;
}
编辑:如果您不允许使用“
x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1)));
并记住以下摘录
请注意,1989 年 ANSI C 规范没有指定结果
签名右移,所以这些是不可移植的。如果抛出异常
在溢出时,x 和 y 的值应该是无符号的或强制转换为
减法无符号以避免不必要地抛出
例外,但是右移需要一个带符号的操作数来产生
负数时全部为一位,因此在此处强制转换为已签名
编辑 II:这应该适用于您发布的规范:
#include <stdio.h>
int getMax(int x, int y, int z) {
int r = (x + ~((x+~y+1) & ((x+~y+1) >> 31))+1); // if possible use sizeof(int)*sizeof(char)+~0 instead of 31
int r2 = (z + ~((z+~r+1) & ((z+~r+1) >> 31))+1); // if possible use sizeof(int)*sizeof(char)+~0 instead of 31
return r2;
}
int main(void) {
unsigned int a = 5, b = 7, c = 1;
printf("%d", getMax(a,b,c));
return 0;
}
请注意,如果您可以使用 sizeof() 而不是仅仅假设 int 是 4 个字节(并非在所有平台上都如此),那会更好。