web-dev-qa-db-ja.com

if-elseまたは他の比較演算子を使用せずに最大2つの整数を見つけるこのスニペットを説明してください。

最大2つの数値を見つけます。 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;  
}
72
SuperMan
int getMax(int a, int b) {
    int c = a - b;
    int k = (c >> 31) & 0x1;
    int max = a - k * c;
    return max;
}

これを分析してみましょう。この最初の行は簡単そうに見えます-abの違いを保存します。この値は、a < bの場合は負であり、それ以外の場合は非負です。実際にはここにバグがあります-数値abの差が大きすぎて整数に収まらない場合、未定義の動作につながります-おっと!そこで、ここでは起こらないと仮定しましょう。

次の行では、

int k = (c >> 31) & 0x1;

cの値が負であるかどうかを確認するという考え方です。事実上すべての現代のコンピューターでは、数字は2の補数と呼ばれる形式で保存されます。数字の正ビットは、数字が正の場合は0、負の場合は1です。さらに、ほとんどの整数は32ビットです。 (c >> 31)は、数値を31ビット下方にシフトし、数値の最上位ビットをスポットの最下位ビットに残します。この数値を取得して1(最後のビットを除くすべてのバイナリ表現が0)とANDをとる次のステップでは、上位ビットがすべて消去され、最下位ビットが得られます。 c >> 31の最下位ビットはcの最上位ビットであるため、cの最上位ビットを0または1として読み取ります。cの場合、最上位ビットは1です。 1の場合、これはcが負(1)か正(0)かを確認する方法です。この推論を上記と組み合わせることで、ka < 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

これも正しい最大値です。

116
templatetypedef

さあ: (a + b) / 2 + |a - b| / 2

28
mike.dld

ビット単位のハックを使用する

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)

ソース: Bit Twiddling Hacks by Sean Eron Anderson

18
Prasoon Saurav
(sqrt( a*a + b*b - 2*a*b ) + a + b) / 2

これは mike.dldのソリューション と同じテクニックに基づいていますが、ここで私がやっていることは「明白」ではありません。 「abs」操作は何かの記号を比較しているように見えますが、ここではsqrt()が常に正の平方根を返すという事実を利用しています。再度ルート化し、a + 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になります

11
CashCow

最も簡単な答えは以下です。

#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);
}
8
novice
int max(int i, int j) {
    int m = ((i-j) >> 31);
    return (m & j) + ((~m) & i);
}

このソリューションは、乗算を回避します。 mは0x00000000または0xffffffffになります

5
vikky.rk

シフトのアイデアを使用して、他の人が投稿した記号を抽出する方法は次のとおりです。

max (a, b) = new[] { a, b } [((a - b) >> 31) & 1]

これにより、インデックスが2つの数値の差の符号ビットであるarray-elementによって指定された最大数を持つ配列に2つの数値がプッシュされます。

次のことに注意してください。

  1. 違い (a - b)オーバーフローする可能性があります。
  2. 数字に符号がなく、>>演算子はlogical右シフト、& 1は不要です。
3
Ani

これが私が仕事をする方法だ。読みやすいとは言えないかもしれませんが、「Xを実行する明白な方法を使用せずにXを実行するにはどうすればよいか」から始めると、それを期待する必要があります。 dは、問題を見るために非常に珍しいシステムを見つける必要があります。

#define BITS (CHAR_BIT * sizeof(int) - 1)

int findmax(int a, int b) { 
    int rets[] = {a, b};
    return rets[unsigned(a-b)>>BITS];
}

これには、質問で示したものよりもいくつかの利点があります。まず、32ビット整数用にハードコーディングされるのではなく、シフトの正しいサイズを計算します。第二に、ほとんどのコンパイラーでは、コンパイル時にすべての乗算が発生することが予想されるため、実行時に残るのは、単純なビット操作(減算とシフト)の後にロードとリターンが続くことです。要するに、これは、オリジナルが実行時に発生しなければならない乗算を使用した最小のマイクロコントローラでさえ、かなり高速であることはほぼ確実であるため、デスクトップマシンではおそらくかなり高速ですが、多くの場合、かなり高速です小さなマイクロコントローラーでは少し遅くなります。

3
Jerry Coffin

これらの行が行っていることは次のとおりです。

cはa-bです。 cが負の場合、a <b。

kはcの32ビット目で、cの符号ビットです(32ビット整数を想定しています。64ビット整数のプラットフォームで実行した場合、このコードは機能しません)。 31ビットを右にシフトして右端の31ビットを削除し、符号ビットを右端に残してから、1を加算して左のすべてのビットを削除します(cが負の場合は1で埋められます)。したがって、cが負の場合、kは1、cが正の場合は0になります。

次に、max = a-k * c。 cが0の場合、これはa> = bを意味するため、maxはa-0 * c = aです。 cが1の場合、これはa <bであり、a-1 * c = a-(a-b)= a-a + b = bであることを意味します。

全体として、より大きいまたはより小さい演算の使用を避けるために、単に差の符号ビットを使用しています。このコードは比較を使用しないと言うのは正直言って少しばかげています。 cは、aとbを比較した結果です。コードは比較演算子を使用していません。多くのアセンブリコードで同様のことを行うには、単に数値を減算し、ステータスレジスタに設定された値に基づいてジャンプします。

また、これらのソリューションはすべて、2つの数値が整数であると想定していることも付け加えてください。それらが浮動小数点数、倍精度数、またはより複雑なもの(BigInts、Rational数値など)である場合は、実際に比較演算子を使用する必要があります。通常、ビットトリックはそれらを行いません。

2
Keith Irwin

論理操作のないgetMax()関数

int getMax(int a, int b){
    return (a+b+((a-b)>>sizeof(int)*8-1|1)*(a-b))/2;
}

説明:

「マックス」を粉砕して、

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

整数の正数では、最初のビット(符号ビット)は;です。負の場合、-1です。ビットを右(>>)にシフトすることにより、最初のビットをキャプチャできます。

右シフト中、空のスペースは符号ビットで埋められます。したがって、1110001 >> 2 = 000111、一方、10110001 >> 2 = 111011

その結果、8ビットの数値シフトでは、7ビットが生成されます-1 1 1 1 1 1 1 [0または1]負の値、または0 0 0 0 0 0 [ 0または1]正の場合。

[〜#〜] or [〜#〜]操作が000001(= 1)で実行される場合、負の数は11111111(=- 1)、および正-000001(= 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 ];
}
1
Minhas Kamal
#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");
}
0
Chirag

私が提供しているコードは、2つの数値の最大値を見つけるためのもので、数値は任意のデータ型(整数、浮動)にできます。入力数値が等しい場合、関数は数値を返します。

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

説明

  • 関数は最初に引数をdoubleとして受け取り、戻り値の型をdoubleにします。これは、すべてのタイプの最大値を見つけることができる単一の関数を作成するためです。整数型の数値が指定されている場合、または一方が整数で他方が浮動小数点である場合、暗黙的な変換により、関数を使用して整数の最大値を見つけることもできます。
  • 基本的なロジックは単純です。たとえば、ab> 0(つまり差が正)の場合は2つの数値a&bがあり、ab == 0の場合はaが最大で、ab <0(つまりdiffは- ve)bは最大です。
  • 符号ビットは、メモリ内の最上位ビット(MSB)として保存されます。 MSBが1で、その逆の場合。 MSBが1または0であるかどうかを確認するには、MSBをLSB位置にシフトし、Bitwise&を1に設定します。結果が1の場合、数値は-veまたはnoです。 + veです。この結果は次のステートメントによって取得されます。

    int_diff >>(sizeof(int)* 8-1)&1

ここで、MSBからLSBに符号ビットを取得するために、それを右にk-1ビットにシフトします(kは、システムのタイプに応じてメモリに整数を保存するために必要なビット数です)。ここで、sizeof()は、noを取得するために整数を保存するために必要なバイト数を与えるため、k = sizeof(int)* 8です。ビットの場合、それを8で乗算します。右シフトの後、ビット単位の&に1を適用して結果を取得します。

  • 結果を取得した後(rと仮定)、1(-ve diffの場合)および0(+ ve diffの場合)として、結果に2つの数値の差を掛けます。ロジックは次のようになります。

    1. a> bの場合、a-b> 0、つまり+ veであるため、結果は0(つまり、r = 0)になります。したがって、a-(a-b)* r => a-(a-b)* 0になり、「a」が最大値になります。
    2. a <bの場合、a-b <0、つまり-veであるため、結果は1(つまり、r = 1)になります。したがって、a-(a-b)* r => a-(a-b)* 1 => a-a + b => bで、最大値として「b」が得られます。
  • これで2つのポイントが残っています。1。whileループの使用と2. 2.変数 'int_diff'を整数として使用した理由。これらに適切に回答するには、いくつかのポイントを理解する必要があります。

    1. 浮動小数点値は、ビット演算子のオペランドとして使用できません。
    2. 上記の理由により、ビット演算子を使用して差の符号を取得するには整数値で値を取得する必要があります。これらの2つのポイントは、変数 'int_diff'の必要性を整数型として説明しています。
    3. ここで、変数 'diff'の違いを見つけたとします。これらの値の符号に関係なく、 'diff'の値には3つの可能性があります。 (a)。 | diff |> = 1、(b)。 0 <| diff | <1、(c)。 | diff | == 0。
    4. Double値を整数変数に割り当てると、小数部分は失われます。
    5. Case(a)の場合、 'int_diff'の値> 0(つまり、1,2、...)。他の2つの場合、int_diff = 0。
    6. 条件(temp_diff-int_diff)|| 0.0は、diff == 0であるため、両方の数値が等しいかどうかをチェックします。
    7. Diff!= 0の場合、int_diff | 0が真かどうか、つまりcase(b)が真かどうかを確認します
    8. Whileループでは、int_diffの値がdiffの符号も取得するように、int_diffの値をゼロ以外として取得しようとします。
0
ashesh

// C#では、数学ライブラリを使用してminまたはmax関数を実行できます

システムを使用して;

クラスNumberComparator {

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

}

}

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 then(ab)が負の場合、符号は-1を返します。1を追加すると、インデックス0(b)が得られます。b= aの場合、abは0になります。 aまたはbを返す場合、a> bの場合、abは正であり、符号は1を返します。1を追加すると、aが格納されているインデックス2が取得されます。

0
Raj Saraf

以下に、2つの整数値の最大値を取得する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)>> SIGN_BIT_SHIFT-a > bの場合、a - bが正の場合、符号ビットは0で、マスクは0x00.00です。それ以外の場合、a < bなので、a - bは負で、符号ビットは1で、シフト後、0xFF..FFのマスクを取得します
  • (a&〜mask)-マスクが0xFF..FFの場合、~mask0x00..00であり、この値は0です。それ以外の場合、~mask0xFF..FFで、値はaです
  • (b&mask)-マスクが0xFF..FFの場合、この値はbです。それ以外の場合、mask0x00..00で、値は0です。

最後に:

  • a >= ba - bが正の場合、max = a | 0 = aが得られます
  • a < ba - 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);
}

説明:

  • マスクの説明は、方法1と同じです。 a > bの場合、マスクは0x00..00です。それ以外の場合、マスクは0xFF..FFです。
  • マスクが0x00..00の場合、(a ^ b) & mask0x00..00です
  • マスクが0xFF..FFの場合、(a ^ b) & maska ^ bです

最後に:

  • a >= bの場合、a ^ 0x00..00 = aを取得します
  • a < bの場合、a ^ a ^ b = bを取得します
0
Daniel Trugman