最大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;
}
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
の値が負であるかどうかを確認するという考え方です。事実上すべての現代のコンピューターでは、数字は2の補数と呼ばれる形式で保存されます。数字の正ビットは、数字が正の場合は0、負の場合は1です。さらに、ほとんどの整数は32ビットです。 (c >> 31)
は、数値を31ビット下方にシフトし、数値の最上位ビットをスポットの最下位ビットに残します。この数値を取得して1(最後のビットを除くすべてのバイナリ表現が0)とANDをとる次のステップでは、上位ビットがすべて消去され、最下位ビットが得られます。 c >> 31
の最下位ビットはc
の最上位ビットであるため、c
の最上位ビットを0または1として読み取ります。c
の場合、最上位ビットは1です。 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
これも正しい最大値です。
さあ: (a + b) / 2 + |a - b| / 2
ビット単位のハックを使用する
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)
(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になります
最も簡単な答えは以下です。
#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);
}
int max(int i, int j) {
int m = ((i-j) >> 31);
return (m & j) + ((~m) & i);
}
このソリューションは、乗算を回避します。 mは0x00000000または0xffffffffになります
シフトのアイデアを使用して、他の人が投稿した記号を抽出する方法は次のとおりです。
max (a, b) = new[] { a, b } [((a - b) >> 31) & 1]
これにより、インデックスが2つの数値の差の符号ビットであるarray-elementによって指定された最大数を持つ配列に2つの数値がプッシュされます。
次のことに注意してください。
(a - b
)オーバーフローする可能性があります。>>
演算子はlogical右シフト、& 1
は不要です。これが私が仕事をする方法だ。読みやすいとは言えないかもしれませんが、「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ビット整数用にハードコーディングされるのではなく、シフトの正しいサイズを計算します。第二に、ほとんどのコンパイラーでは、コンパイル時にすべての乗算が発生することが予想されるため、実行時に残るのは、単純なビット操作(減算とシフト)の後にロードとリターンが続くことです。要するに、これは、オリジナルが実行時に発生しなければならない乗算を使用した最小のマイクロコントローラでさえ、かなり高速であることはほぼ確実であるため、デスクトップマシンではおそらくかなり高速ですが、多くの場合、かなり高速です小さなマイクロコントローラーでは少し遅くなります。
これらの行が行っていることは次のとおりです。
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数値など)である場合は、実際に比較演算子を使用する必要があります。通常、ビットトリックはそれらを行いません。
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 ];
}
#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");
}
私が提供しているコードは、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 ));
}
説明
符号ビットは、メモリ内の最上位ビット(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つの数値の差を掛けます。ロジックは次のようになります。
これで2つのポイントが残っています。1。whileループの使用と2. 2.変数 'int_diff'を整数として使用した理由。これらに適切に回答するには、いくつかのポイントを理解する必要があります。
// 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が取得されます。
以下に、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
の場合、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
を取得します