كيف يمكنني برمجيا العودة الحد الأقصى من عددين من دون استخدام أي عوامل المقارنة ودون استخدام إذا، آخر، وما إلى ذلك؟

StackOverflow https://stackoverflow.com/questions/227383

سؤال

وكيف يمكنني برمجيا العودة الحد الأقصى من عددين من دون استخدام أي عوامل المقارنة ودون استخدام if، else، وما إلى ذلك؟

هل كانت مفيدة؟

المحلول

والأقصى: // سوف يضع MAX (أ، ب) في

a -= b;
a &= (~a) >> 31;
a += b;

و:

والباحث أ، ب؛

ودقيقة: // سوف يضع MIN (أ، ب) في

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) لتشبع بت تسجيل، ولكن عادة ما يكون هذا كافيا. أو يمكنك اختبار بت عالية، ودائما متعة.

وأعتقد أنني قد حصلت عليه.

int data[2] = {a,b};
int c = a - b;
return data[(int)((c & 0x80000000) >> 31)];

وهذا لن يجدي نفعا؟ في الأساس، وانت تأخذ الفرق بين الاثنين، ثم يعود واحدة أو أخرى على أساس بت تسجيل. (وهذه هي الطريقة المعالج لا أكبر من أو أقل من أي حال.) حتى إذا بت علامة 0، ترجع، لأن أكبر من أو يساوي ب. إذا بت تسجيل هو 1، والعودة ب، لطرح ب من تسبب في نتيجة الذهاب سلبي، مشيرا إلى أن ب كانت أكبر من أ. فقط تأكد من أن [إينتس] الخاصة بك وقعت 32bits.

في العالم الرياضيات:

max(a+b) = ( (a+b) + |(a-b)| ) / 2
min(a-b) = ( (a+b) - |(a-b)| ) / 2

وبصرف النظر عن كونها صحيحة رياضيا أنها لا يجعل افتراضات حول حجم بت تحويل العمليات تحتاج إلى القيام به.

و|x| لتقف على القيمة المطلقة ل x.

تعليق:

وأنت على حق، وقد نسي القيمة المطلقة. هذا يجب أن تكون صالحة لجميع أ، ب إيجابية أو سلبية

وعودة (أ> ب أ: ب)؛

أو

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

وهذا هو حزقيل، ولكنها سوف تكون هي نفسها في أي لغة أخرى. يجب C / C # الناس استخدام "SGN" (أو "علامة"؟) بدلا من السر.

لاحظ أن هذا سيعمل على [إينتس] من حجم التعسفي وعلى ريال كذلك.

ومن (الكاتب virii الشهير) من المادة z0mbie في "تعدد الأشكال الألعاب"، ربما ستجد أنه من المفيد:

#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))

وهتافات

وهذا هو نوع من الغش، وذلك باستخدام لغة التجميع، لكنها مثيرة للاهتمام مع ذلك:


// 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 max(int a, int b)
{
   return ((a - b) >> 31) ? b : a;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top