找到最多两个数字。您不应该使用if-else或任何其他比较运算符。我在网上公告板上发现了这个问题,所以我想我应该在StackOverflow中提问
实施例 输入:5,10 输出:10
我找到了这个解决方案,有人可以帮我理解这些代码行
int getMax(int a, int b) {
int c = a - b;
int k = (c >> 31) & 0x1;
int max = a - k * c;
return max;
}
答案 0 :(得分:116)
int getMax(int a, int b) {
int c = a - b;
int k = (c >> 31) & 0x1;
int max = a - k * c;
return max;
}
让我们剖析一下。第一行看起来很简单 - 它存储a
和b
的差异。如果a < b
,此值为负,否则为非负。这里实际上存在一个错误 - 如果数字a
和b
之间的差异太大而无法放入整数,这将导致未定义的行为 - 哎呀!所以我们假设这不会发生。
在下一行,即
int k = (c >> 31) & 0x1;
我们的想法是检查c
的值是否为负值。在几乎所有现代计算机中,数字以称为二进制补码的格式存储,其中如果数字为正,则数字的最高位为0,如果数字为负,则为1。而且,大多数是32位。 (c >> 31)
将数字向下移动31位,在最低位的位置留下数字的最高位。获取此数字并将其与1进行AND运算(除了最后一位之外,其二进制表示为0)的下一步将擦除所有较高位,并为您提供最低位。由于c >> 31
的最低位是c
的最高位,因此将c
的最高位读取为0或1.由于最高位为1 iff c
是1,这是检查c
是否为负(1)还是为正(0)的方法。将此推理与上述相结合,如果k
,则a < b
为1,否则为0。
最后一步是这样做:
int max = a - k * c;
如果a < b
,则k == 1
和k * c = c = a - b
,等等
a - k * c = a - (a - b) = a - a + b = b
从a < b
开始,这是正确的最大值。否则,如果是a >= b
,则k == 0
和
a - k * c = a - 0 = a
这也是正确的最大值
答案 1 :(得分:28)
我们走了:(a + b) / 2 + |a - b| / 2
答案 2 :(得分:19)
使用按位黑客
r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
如果您知道INT_MIN <= x - y <= INT_MAX,
,那么您可以使用以下内容,因为(x - y)
仅需要评估一次,因此速度更快。
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)
答案 3 :(得分:11)
(sqrt( a*a + b*b - 2*a*b ) + a + b) / 2
这是基于与mike.dld's solution相同的技术,但在这里我不太“明显”。 “abs”操作看起来像是在比较某些东西的符号,但我在这里利用了sqrt()总是会返回正平方根的事实,所以我正在平方(ab)将其全部写出来然后正方形 - 再次生根,添加+ b并除以2.
你会看到它总是有效:例如用户的10和5的例子你得到sqrt(100 + 25 - 100)= 5然后加10和5得到20除以2得到10。
如果我们使用9和11作为我们的数字(sqrt(121 + 81 - 198)+ 11 + 9)/ 2 =(sqrt(4)+ 20)/ 2 = 22/2 = 11
答案 4 :(得分:8)
最简单的答案如下。
#include <math.h>
int Max(int x, int y)
{
return (float)(x + y) / 2.0 + abs((float)(x - y) / 2);
}
int Min(int x, int y)
{
return (float)(x + y) / 2.0 - abs((float)(x - y) / 2);
}
答案 5 :(得分:4)
int max(int i, int j) {
int m = ((i-j) >> 31);
return (m & j) + ((~m) & i);
}
此解决方案避免了乘法。 m将为0x00000000或0xffffffff
答案 6 :(得分:3)
使用移位的想法来提取他人发布的标志,这是另一种方式:
max (a, b) = new[] { a, b } [((a - b) >> 31) & 1]
这将两个数字推入一个数组,其中最大数字由array-element给出,其索引是两个数字之差的符号位。
请注意:
(a - b
)可能会溢出。>>
运算符引用逻辑右移,则& 1
是不必要的。答案 7 :(得分:3)
以下是我认为我会做的工作。它并不像你想的那样可读,但是当你开始“我怎么做X而不使用明显的做X的方式时,你必须要有这样的期望。 从理论上讲,这也放弃了一些可移植性,但你必须找到一个非常不寻常的系统才能看到问题。
#define BITS (CHAR_BIT * sizeof(int) - 1)
int findmax(int a, int b) {
int rets[] = {a, b};
return rets[unsigned(a-b)>>BITS];
}
这确实比问题中显示的有一些优点。首先,它计算正确的移位大小,而不是对32位整数进行硬编码。其次,对于大多数编译器,我们可以期望所有乘法都在编译时发生,因此在运行时剩下的所有内容都是微不足道的位操作(减法和移位),然后是加载和返回。简而言之,这几乎肯定会非常快,即使在最小的微控制器上,原始使用的乘法必须在运行时发生,所以虽然它可能在台式机上相当快,但它通常是相当快的在小型微控制器上慢一点。
答案 8 :(得分:2)
以下是这些行正在做的事情:
c是a-b。如果c为负,则a
k是c的第32位,它是c的符号位(假设32位整数。如果在具有64位整数的平台上完成,则此代码将不起作用)。它向右移31位以移除最右边的31位,在最右边的位置留下符号位,然后用1除去它以移除左边的所有位(如果c为负,则将填充1s)。因此,如果c为负,k将为1,如果c为正,则k为0。
然后max = a - k * c。如果c为0,则这意味着a> = b,因此max是-0 * c = a。如果c为1,这意味着a&lt; b然后a - 1 * c = a - (a - b)= a - a + b = b。
总的来说,它只是使用差异的符号位来避免使用大于或小于操作。老实说,这段代码不使用比较,实在是有点傻。 c是比较a和b的结果。代码只是不使用比较运算符。您可以在许多汇编代码中执行类似的操作,只需减去数字然后根据状态寄存器中设置的值跳转。
我还应该补充一点,所有这些解决方案都假设这两个数字是整数。如果它们是浮点数,双精度数或更复杂的东西(BigInts,Rational数字等),那么你真的必须使用比较运算符。比特技巧通常不适用于那些人。
答案 9 :(得分:1)
int getMax(int a, int b){
return (a+b+((a-b)>>sizeof(int)*8-1|1)*(a-b))/2;
}
让我们粉碎&#39; max&#39;成碎片,
max
= ( max + max ) / 2
= ( max + (min+differenceOfMaxMin) ) / 2
= ( max + min + differenceOfMaxMin ) / 2
= ( max + min + | max - min | ) ) / 2
所以函数看起来应该是这样的 -
getMax(a, b)
= ( a + b + absolute(a - b) ) / 2
现在,
absolute(x)
= x [if 'x' is positive] or -x [if 'x' is negative]
= x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] )
在整数正数中,第一位(符号位)是 - 0 ;否定它是 - 1 。通过向右移位(&gt;&gt;),可以捕获第一位。
在右移期间,空格由符号位填充。所以 01110001&gt;&gt; 2 = 00011100 ,而 10110001&gt;&gt; 2 = 11101100 。
因此,对于8位数字移位,7位将产生 - 1 1 1 1 1 1 [0或1] 为负,或 0 0 0 0 0 0 0 [0或1] 表示正面。
现在,如果使用 00000001(= 1)执行 OR 操作,则负数产生 - 11111111(= -1),并且positive- 00000001(= 1)。
所以,
absolute(x)
= x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] )
= x * ( ( x >> (numberOfBitsInInteger-1) ) | 1 )
= x * ( ( x >> ((numberOfBytesInInteger*bitsInOneByte) - 1) ) | 1 )
= x * ( ( x >> ((sizeOf(int)*8) - 1) ) | 1 )
最后,
getMax(a, b)
= ( a + b + absolute(a - b) ) / 2
= ( a + b + ((a-b) * ( ( (a-b) >> ((sizeOf(int)*8) - 1) ) | 1 )) ) / 2
另一种方式 -
int getMax(int a, int b){
int i[] = {a, b};
return i[( (i[0]-i[1]) >> (sizeof(int)*8 - 1) ) & 1 ];
}
答案 10 :(得分:0)
没有逻辑运算符,没有库(JS)
function (x, y) {
let z = (x - y) ** 2;
z = z ** .5;
return (x + y + z) / 2
}
答案 11 :(得分:0)
///在C#中,您可以使用数学库来执行最小或最大函数
使用系统;
ClassNumberComparator {
static void Main()
{
Console.Write(" write the first number to compare: ");
double first_Number = double.Parse(Console.ReadLine());
Console.Write(" write the second number to compare: ");
double second_Number = double.Parse(Console.ReadLine());
double compare_Numbers = Math.Max(first_Number, second_Number);
Console.Write("{0} is greater",compare_Numbers);
}
}
答案 12 :(得分:0)
以下是一些 bit-twiddling 方法,可以获得两个整数值的最大值:
方法1
int max1(int a, int b) {
static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1;
int mask = (a - b) >> SIGN_BIT_SHIFT;
return (a & ~mask) | (b & mask);
}
说明:
a > b
则a - b
为正,则符号位为0
,掩码为0x00.00
。否则,a < b
因此a - b
为负数,符号位为1
,移位后,我们会获得0xFF..FF
的掩码0xFF..FF
,则~mask
为0x00..00
,然后此值为0
。否则,~mask
为0xFF..FF
,值为a
0xFF..FF
,则此值为b
。否则,mask
为0x00..00
,值为0
。最后:
a >= b
然后a - b
为正,我们会max = a | 0 = a
a < b
然后a - b
为否定,我们会max = 0 | b = b
方法2
int max2(int a, int b) {
static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1;
int mask = (a - b) >> SIGN_BIT_SHIFT;
return a ^ ((a ^ b) & mask);
}
说明:
a > b
掩码为0x00..00
,则掩码为0xFF..FF
0x00..00
,则(a ^ b) & mask
为0x00..00
0xFF..FF
,则(a ^ b) & mask
为a ^ b
最后:
a >= b
,我们会a ^ 0x00..00 = a
a < b
,我们会a ^ a ^ b = b
答案 13 :(得分:0)
#include<stdio.h>
main()
{
int num1,num2,diff;
printf("Enter number 1 : ");
scanf("%d",&num1);
printf("Enter number 2 : ");
scanf("%d",&num2);
diff=num1-num2;
num1=abs(diff);
num2=num1+diff;
if(num1==num2)
printf("Both number are equal\n");
else if(num2==0)
printf("Num2 > Num1\n");
else
printf("Num1 > Num2\n");
}
答案 14 :(得分:0)
我提供的代码是在两个数字之间找到最大值,数字可以是任何数据类型(整数,浮点数)。如果输入数字相等,则函数返回数字。
double findmax(double a, double b)
{
//find the difference of the two numbers
double diff=a-b;
double temp_diff=diff;
int int_diff=temp_diff;
/*
For the floating point numbers the difference contains decimal
values (for example 0.0009, 2.63 etc.) if the left side of '.' contains 0 then we need
to get a non-zero number on the left side of '.'
*/
while ( (!(int_diff|0)) && ((temp_diff-int_diff)||(0.0)) )
{
temp_diff = temp_diff * 10;
int_diff = temp_diff;
}
/*
shift the sign bit of variable 'int_diff' to the LSB position and find if it is
1(difference is -ve) or 0(difference is +ve) , then multiply it with the difference of
the two numbers (variable 'diff') then subtract it with the variable a.
*/
return a- (diff * ( int_diff >> (sizeof(int) * 8 - 1 ) & 1 ));
}
<强>描述强>
符号位保存为内存中的最高有效位(MSB)。如果MSB为1,反之亦然。为了检查MSB是1还是0,我们将MSB移位到LSB位置并按位和&amp;如果结果为1则为1,则数字为-ve else no。是+ ve。该结果通过以下声明获得:
int_diff&gt;&gt; (sizeof(int)* 8 - 1)&amp; 1
这里为了获得从MSB到LSB的符号位,我们将其右移到k-1位(其中k是在存储器中保存整数所需的位数,这取决于系统的类型)。这里k = sizeof(int)* 8,因为sizeof()给出了保存整数以获得no所需的字节数。比特,我们乘以8.在右移之后,我们应用按位&amp;用1得到结果。
现在获得结果(让我们假设它为r)为1(对于-ve diff)和0(对于+ ve diff)我们将结果乘以两个数的差值,逻辑是给出如下:
现在剩下两点1.使用while循环和2.为什么我使用变量'int_diff'作为整数。要正确回答这些问题,我们必须了解一些观点:
答案 15 :(得分:0)
static int mymax(int a,int b)
{
int[] arr;
arr = new int[3];
arr[0] = b;
arr[1] = a;
arr[2] = a;
return arr[Math.Sign(a - b) + 1];
}
如果b> a然后(ab)将为负数,符号将返回-1,通过加1,我们得到索引0,即b,如果b = a则ab将为0,+ 1将给出1个索引因此如果我们是返回a或b,当a> b然后a-b将为正,sign将返回1,加1,我们得到索引2,其中a存储。
答案 16 :(得分:-2)
问题中描述的逻辑可以解释为如果第一个数字小于0则将被减去,否则将从第一个数字中减去差值以获得第二个数字。 我发现了另外一个数学解决方案,我认为理解这个概念有点简单。
将a和b视为给定数字
c=|a/b|+1;
d=(c-1)/b;
smallest number= a - d*(a-b);
再次,想法是找到0或1的k并将其与两个数的差相乘。最后,应该从第一个数中减去该数,以得到两个数中较小的数。 附:如果第二个数字为零,此解决方案将失败
答案 17 :(得分:-2)
int a=151;
int b=121;
int k=Math.abs(a-b);
int j= a+b;
double k1=(double)(k);
double j1= (double) (j);
double c=Math.ceil(k1/2) + Math.floor(j1/2);
int c1= (int) (c);
System.out.println(" Max value = " + c1);
答案 18 :(得分:-3)
有一种方法
public static int Min(int a, int b)
{
int dif = (int)(((uint)(a - b)) >> 31);
return a * dif + b * (1 - dif);
}
和一个
return (a>=b)?b:a;
答案 19 :(得分:-4)
猜猜我们可以将这些数字与其按位比较相乘,例如:
int max=(a>b)*a+(a<=b)*b;