簡體   English   中英

如何在不使用任何比較運算符和不使用 if、else 等的情況下以編程方式返回兩個整數的最大值?

[英]How do I programmatically return the max of two integers without using any comparison operators and without using if, else, etc?

如何在不使用任何比較運算符且不使用ifelse等的情況下以編程方式返回兩個整數的最大值?

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 位簽名的。

來自 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))

干杯

返回 (a > b ? a : b);

或者

int max(int a, int b)
{
        int x = (a - b) >> 31;
        int y = ~x;
        return (y & a) | (x & b); 
}

不像上面的那么時髦……但是……

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");
}

這是我在 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 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));
}

兩個版本都適用於所有整數類型。

請注意, gccclang都為上述函數生成了無分支代碼,並且clang為這兩種替代方案生成了相同的最佳代碼,如在Godbolt Compiler Explorer session 中所見。

int max(int a, int b)
{
   return ((a - b) >> 31) ? b : a;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM