C 等价于大于运算符的位运算
我正在研究一个函数,它基本上可以看出两个int中哪个更大。传递的参数是C 等价于大于运算符的位运算,c,binary,bit-manipulation,C,Binary,Bit Manipulation,我正在研究一个函数,它基本上可以看出两个int中哪个更大。传递的参数是232位整数。诀窍是只允许使用!~ |&>^(无强制转换,除带符号的int、*、/、-等以外的其他数据类型) 到目前为止,我的想法是将这两个二进制文件放在一起,以查看它们不共享的1值的所有位置。然后我想做的是取那个值并将最左边的1隔离。然后看看哪一个有这个价值。然后该值将更大。 (假设我们使用8位整数而不是32位整数)。 如果传递的两个值分别为01011011和01101001 我对它们使用了^来获得00100010。 然后我
2
32位整数。诀窍是只允许使用!~ |&>^代码>(无强制转换,除带符号的int、*、/、-等以外的其他数据类型)
到目前为止,我的想法是将这两个二进制文件放在一起,以查看它们不共享的1
值的所有位置。然后我想做的是取那个值并将最左边的1
隔离。然后看看哪一个有这个价值。然后该值将更大。
(假设我们使用8位整数而不是32位整数)。
如果传递的两个值分别为01011011
和01101001
我对它们使用了^
来获得00100010
。
然后我想让它成为00100000
,换句话说01xxxxxx->01000000
然后&
使用第一个数字
编码>结果并返回它。
如果是1
,则第一个#
较大
关于如何01xxxxxx->01000000
或其他有帮助的方法,您有什么想法吗
忘了注意:没有ifs、whiles、fors等…编辑:
好的,代码有一些问题,但我修改了它,并进行了以下工作
此辅助功能比较第n个有效数字:
int compare ( int a, int b, int n )
{
int digit = (0x1 << n-1);
if ( (a & digit) && (b & digit) )
return 0; //the digit is the same
if ( (a & digit) && !(b & digit) )
return 1; //a is greater than b
if ( !(a & digit) && (b & digit) )
return -1; //b is greater than a
}
编辑:约束使底部的简单方法无效。我正在添加二进制搜索函数和最终比较,以检测更大的值:
unsigned long greater(unsigned long a, unsigned long b) {
unsigned long x = a;
unsigned long y = b;
unsigned long t = a ^ b;
if (t & 0xFFFF0000) {
x >>= 16;
y >>= 16;
t >>= 16;
}
if (t & 0xFF00) {
x >>= 8;
y >>= 8;
t >>= 8;
}
if (t & 0xf0) {
x >>= 4;
y >>= 4;
t >>= 4;
}
if ( t & 0xc) {
x >>= 2;
y >>= 2;
t >>= 2;
}
if ( t & 0x2) {
x >>= 1;
y >>= 1;
t >>= 1;
}
return (x & 1) ? a : b;
}
我们的想法是从我们感兴趣的单词的最重要的一半开始,看看其中是否有任何设定位。如果有,那么我们不需要最低有效的一半,所以我们将不需要的位移开。如果不是,我们什么也不做(反正一半是零,所以不会碍事)。由于我们无法跟踪移位量(这需要加法),因此我们也会移位原始值,以便我们可以进行最后的和
以确定较大的数字。我们用上一个掩码的一半大小重复这个过程,直到我们将感兴趣的位折叠到位位置0为止
我不是故意在这里加上同样的例子的
旧答案:
对于家庭作业来说,最简单的方法可能是最好的。一旦获得了不匹配的位值,就从另一个掩码0x8000000(或适合字大小的任何合适的最大位位置)开始,并保持右移,直到达到设置在不匹配值中的位为止。如果右移以0结束,则不匹配值为0
我假设您已经知道确定较大数字所需的最后一步。这里有一个无循环版本,它比较O(lg b)运算中的无符号整数,其中b是机器的字长。请注意,OP只说明了signed int
,没有其他数据类型,因此此答案的顶部似乎不符合OP的规范。(扰流板版本与底部相同。)
请注意,我们要捕获的行为是,对于a
而言,最重要的位不匹配是1
,对于b
而言,最重要的位不匹配是0
。另一种思考方式是a
中的任何位大于b
中的相应位意味着a
大于b
,只要a
中没有早于b
中相应位的位
为此,我们计算a
中大于b
中相应位的所有位,同样地计算a
中小于b
中相应位的所有位。我们现在想屏蔽掉所有低于“小于”位的“大于”位,所以我们将所有的“小于”位都涂抹到右边,制作一个屏蔽:最重要的位设置一直到最不重要的位现在是1
现在我们所要做的就是通过使用简单的位屏蔽逻辑删除“大于”位集
如果ab
,则结果值为0。在后一种情况下,如果我们希望它是1
,我们可以执行类似的涂抹技巧,只需查看最低有效位
#include <stdio.h>
// Works for unsigned ints.
// Scroll down to the "actual algorithm" to see the interesting code.
// Utility function for displaying binary representation of an unsigned integer
void printBin(unsigned int x) {
for (int i = 31; i >= 0; i--) printf("%i", (x >> i) & 1);
printf("\n");
}
// Utility function to print out a separator
void printSep() {
for (int i = 31; i>= 0; i--) printf("-");
printf("\n");
}
int main()
{
while (1)
{
unsigned int a, b;
printf("Enter two unsigned integers separated by spaces: ");
scanf("%u %u", &a, &b);
getchar();
printBin(a);
printBin(b);
printSep();
/************ The actual algorithm starts here ************/
// These are all the bits in a that are less than their corresponding bits in b.
unsigned int ltb = ~a & b;
// These are all the bits in a that are greater than their corresponding bits in b.
unsigned int gtb = a & ~b;
ltb |= ltb >> 1;
ltb |= ltb >> 2;
ltb |= ltb >> 4;
ltb |= ltb >> 8;
ltb |= ltb >> 16;
// Nonzero if a > b
// Zero if a <= b
unsigned int isGt = gtb & ~ltb;
// If you want to make this exactly '1' when nonzero do this part:
isGt |= isGt >> 1;
isGt |= isGt >> 2;
isGt |= isGt >> 4;
isGt |= isGt >> 8;
isGt |= isGt >> 16;
isGt &= 1;
/************ The actual algorithm ends here ************/
// Print out the results.
printBin(ltb); // Debug info
printBin(gtb); // Debug info
printSep();
printBin(isGt); // The actual result
}
}
我会留下来解释为什么它由您决定。一个无符号变量,它可以使用逻辑(&&,| | |)和比较(!=,=)
对于签名用户,可以扩展到以下内容:
int isgt(int a, int b)
{
return
(a != b) &&
(
(!(0x80000000 & a) && 0x80000000 & b) || /* if a >= 0 && b < 0 */
(!(0x80000000 & a) && b == 0) ||
/* Two more lines, can add them if you like, but as it is homework
* I'll leave it up to you to decide.
* Hint: check on "both negative" and "both not negative". */
)
;
}
使用此项测试:
void test_isgt(int a, int b)
{
fprintf(stdout,
"%11d > %11d = %d : %d %s\n",
a, b,
isgt(a, b), (a > b),
isgt(a, b) != (a>b) ? "BAD!" : "OK!");
}
结果:
33 > 0 = 1 : 1 OK!
-33 > 0 = 0 : 0 OK!
0 > 33 = 0 : 0 OK!
0 > -33 = 1 : 1 OK!
0 > 0 = 0 : 0 OK!
33 > 33 = 0 : 0 OK!
-33 > -33 = 0 : 0 OK!
-5 > -33 = 1 : 1 OK!
-33 > -5 = 0 : 0 OK!
-2147483647 > 2147483647 = 0 : 0 OK!
2147483647 > -2147483647 = 1 : 1 OK!
2147483647 > 2147483647 = 0 : 0 OK!
2147483647 > 0 = 1 : 1 OK!
0 > 2147483647 = 0 : 0 OK!
虽然我不想做别人的家庭作业,但我还是忍不住要做这件事:)我相信其他人可以想出一个更紧凑的…但这是我的…效果很好,包括负数
编辑:不过有几个bug。我将把它留给OP去发现它并修复它
#include<unistd.h>
#include<stdio.h>
int a, b, i, ma, mb, a_neg, b_neg, stop;
int flipnum(int *num, int *is_neg) {
*num = ~(*num) + 1;
*is_neg = 1;
return 0;
}
int print_num1() {
return ((a_neg && printf("bigger number %d\n", mb)) ||
printf("bigger number %d\n", ma));
}
int print_num2() {
return ((b_neg && printf("bigger number %d\n", ma)) ||
printf("bigger number %d\n", mb));
}
int check_num1(int j) {
return ((a & j) && print_num1());
}
int check_num2(int j) {
return ((b & j) && print_num2());
}
int recursive_check (int j) {
((a & j) ^ (b & j)) && (check_num1(j) || check_num2(j)) && (stop = 1, j = 0);
return(!stop && (j = j >> 1) && recursive_check(j));
}
int main() {
int j;
scanf("%d%d", &a, &b);
ma = a; mb = b;
i = (sizeof (int) * 8) - 1;
j = 1 << i;
((a & j) && flipnum(&a, &a_neg));
((b & j) && flipnum(&b, &b_neg));
j = 1 << (i - 1);
recursive_check(j);
(!stop && printf("numbers are same..\n"));
}
#包括
#包括
int a,b,i,ma,mb,a_neg,b_neg,stop;
int flipnum(int*num,int*is_neg){
*num=~(*num)+1;
*is_neg=1;
返回0;
}
int print_num1(){
返回((a_neg&&printf(“较大的数字%d\n”,mb))||
printf(“较大的数字%d\n”,ma));
}
int print_num2(){
返回((b_neg&&printf(“较大的数字%d\n”,ma))||
printf(“较大的数字%d\n”,mb));
}
整数检查数m1(整数j){
返回((a&j)和打印num1());
}
内部检查\u num2(内部j){
返回((b&j)和打印(num2());
}
int递归检查(int j){
(a&j)^(b&j)&&&(check_num1(j)| check_num2(j))&&&(stop=1,j=0);
返回(!停止和(j=j>>1)和递归检查(j));
}
int main(){
int j;
scanf(“%d%d”、&a和&b);
ma=a;mb=b;
i=(sizeof(int)*8)-1;
j=1要将001xxxxx
转换为00100000
,首先执行:
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
(这是针对8位的;要将其扩展到32位,请在序列开始处添加8和16的移位)
这只剩下
#include <limits.h>
static const int INT_NEG = (1 << ((sizeof(int) * CHAR_BIT) - 1));
void test_isgt(int a, int b)
{
fprintf(stdout,
"%11d > %11d = %d : %d %s\n",
a, b,
isgt(a, b), (a > b),
isgt(a, b) != (a>b) ? "BAD!" : "OK!");
}
33 > 0 = 1 : 1 OK!
-33 > 0 = 0 : 0 OK!
0 > 33 = 0 : 0 OK!
0 > -33 = 1 : 1 OK!
0 > 0 = 0 : 0 OK!
33 > 33 = 0 : 0 OK!
-33 > -33 = 0 : 0 OK!
-5 > -33 = 1 : 1 OK!
-33 > -5 = 0 : 0 OK!
-2147483647 > 2147483647 = 0 : 0 OK!
2147483647 > -2147483647 = 1 : 1 OK!
2147483647 > 2147483647 = 0 : 0 OK!
2147483647 > 0 = 1 : 1 OK!
0 > 2147483647 = 0 : 0 OK!
#include<unistd.h>
#include<stdio.h>
int a, b, i, ma, mb, a_neg, b_neg, stop;
int flipnum(int *num, int *is_neg) {
*num = ~(*num) + 1;
*is_neg = 1;
return 0;
}
int print_num1() {
return ((a_neg && printf("bigger number %d\n", mb)) ||
printf("bigger number %d\n", ma));
}
int print_num2() {
return ((b_neg && printf("bigger number %d\n", ma)) ||
printf("bigger number %d\n", mb));
}
int check_num1(int j) {
return ((a & j) && print_num1());
}
int check_num2(int j) {
return ((b & j) && print_num2());
}
int recursive_check (int j) {
((a & j) ^ (b & j)) && (check_num1(j) || check_num2(j)) && (stop = 1, j = 0);
return(!stop && (j = j >> 1) && recursive_check(j));
}
int main() {
int j;
scanf("%d%d", &a, &b);
ma = a; mb = b;
i = (sizeof (int) * 8) - 1;
j = 1 << i;
((a & j) && flipnum(&a, &a_neg));
((b & j) && flipnum(&b, &b_neg));
j = 1 << (i - 1);
recursive_check(j);
(!stop && printf("numbers are same..\n"));
}
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
x ^= x >> 1;
int isGt(int a, int b)
{
int diff = a ^ b;
diff |= diff >> 1;
diff |= diff >> 2;
diff |= diff >> 4;
diff |= diff >> 8;
diff |= diff >> 16;
//1+ on GT, 0 otherwise.
diff &= ~(diff >> 1) | 0x80000000;
diff &= (a ^ 0x80000000) & (b ^ 0x7fffffff);
//flatten back to range of 0 or 1.
diff |= diff >> 1;
diff |= diff >> 2;
diff |= diff >> 4;
diff |= diff >> 8;
diff |= diff >> 16;
diff &= 1;
return diff;
}