C 检查两个无符号整数之间的差值是否最大为1
我正在寻找一种快速的方法来检查两个无符号整数之间的差是否最大为1C 检查两个无符号整数之间的差值是否最大为1,c,integer,bit-manipulation,C,Integer,Bit Manipulation,我正在寻找一种快速的方法来检查两个无符号整数之间的差是否最大为1 显然,我可以直接通过x来做,因为wrapparound可以工作,那么就x-y+1怎么样 我正在寻找一种快速的方法来检查两个无符号整数之间的差是否最大为1 通常,一个快速的方法最终会得到一个解决方案,该解决方案大部分时间都有效,但不是全部——从而留下一个bug供未来的程序员解决 这就是这里提出的各种解决方案的情况 一个很好的替代方法是,形成一个测试线束,以1测试正确性2允许分析来评估性能 一个好的方法是让编译优化一个肯定正确的解决方
显然,我可以直接通过x来做,因为wrapparound可以工作,那么就x-y+1怎么样 我正在寻找一种快速的方法来检查两个无符号整数之间的差是否最大为1 通常,一个快速的方法最终会得到一个解决方案,该解决方案大部分时间都有效,但不是全部——从而留下一个bug供未来的程序员解决 这就是这里提出的各种解决方案的情况 一个很好的替代方法是,形成一个测试线束,以1测试正确性2允许分析来评估性能 一个好的方法是让编译优化一个肯定正确的解决方案,比如ref或methodC 下面是功能测试线束
#include <assert.h>
#include <limits.h>
#include <stdio.h>
int ref(unsigned int a, unsigned int b) {
assert(UINT_MAX <= LLONG_MAX);
long long al = a;
long long bl = b;
long long diff = al - bl;
return diff >= -1 && diff <= 1;
}
int method1(unsigned int a, unsigned int b) {
return a - b + 1 <= 2;
}
int method2(unsigned int a, unsigned int b) {
return -~a - b <= 2;
}
int method3(unsigned int a, unsigned int b) {
return ~a + b >= -2u;
}
int method_OP1(unsigned int x, unsigned int y) {
return x <= y + 1 && y <= x + 1;
}
int method_OP2(unsigned int x, unsigned int y) {
return x == (x + y) / 2 || y == (x + y) / 2;
}
int methodC(unsigned int a, unsigned int b) {
return a < b ? ((b - a) <= 1) : ((a - b) <= 1);
}
typedef int (*fun)(unsigned int, unsigned int);
int test1(const char *s, fun f, unsigned int a, unsigned int b) {
int y1 = ref(a, b);
int y2 = f(a, b);
if (y1 != y2) {
printf("%-10s %10u and %10u: ", s, a, b);
printf("ref %d ", y1);
printf("method %d\n", y2);
}
return y1 != y2;
}
int main(void) {
fun f[] = {method1, method2, method3, method_OP1, method_OP2, methodC};
char *s[] = {"method1", "method2", "method3", "method_OP1", "method_OP2",
"methodC"};
int fn = sizeof f / sizeof f[0];
unsigned u[] = {0, 1, 2, 3, //
UINT_MAX - 3, UINT_MAX - 2, UINT_MAX - 1, UINT_MAX};
int n = sizeof u / sizeof u[0];
for (int fi = 0; fi < fn; fi++) {
for (int ia = 0; ia < n; ia++) {
for (int ib = 0; ib < n; ib++) {
if (test1(s[fi], f[fi], u[ia], u[ib]) && 0) {
ia = n;
break;
}
}
}
}
}
如果我们使用,您可能会假设这两种输入类型是相同的,并且在添加它们时没有溢出。然后方法2的失败可以被原谅。这一假设并不直接涵盖
其他方法的失败。一个对所有输入都正确的相对简单的表达式是
(x - y + (y > x)) <= 1
假设>产生0或1,如在C中。您需要哪种快捷键?写得快吗?快速阅读?能很快理解吗?快速编译?快速执行?假设执行速度,它需要比您展示的代码示例快多少?显示的解的计时速度有多快?在无符号数的边界附近如何?Eg:你认为UntuxMax和0之间的差别最多是1吗?毕竟,向其添加1会导致零。你最初的表达没有,但可能情况并非如此considered@harold:不,我没有。这种差异与算术无关,与补码无关。我问题中的两个选项假设在添加时没有溢出。@注意,没有2s补码问题或未签名的问题。有溢出,但没有2的补码。假设它有效,x-y+1,如果x==0和y==MAX,那么x-y+1==0,那么就不完美了。也许-a-b~a+b>=-2u就少了一次运算。@chuxone@goodvibration请注意,这个技巧确实考虑到UntuxMax在零的1以内。
#include <assert.h>
#include <limits.h>
#include <stdio.h>
int ref(unsigned int a, unsigned int b) {
assert(UINT_MAX <= LLONG_MAX);
long long al = a;
long long bl = b;
long long diff = al - bl;
return diff >= -1 && diff <= 1;
}
int method1(unsigned int a, unsigned int b) {
return a - b + 1 <= 2;
}
int method2(unsigned int a, unsigned int b) {
return -~a - b <= 2;
}
int method3(unsigned int a, unsigned int b) {
return ~a + b >= -2u;
}
int method_OP1(unsigned int x, unsigned int y) {
return x <= y + 1 && y <= x + 1;
}
int method_OP2(unsigned int x, unsigned int y) {
return x == (x + y) / 2 || y == (x + y) / 2;
}
int methodC(unsigned int a, unsigned int b) {
return a < b ? ((b - a) <= 1) : ((a - b) <= 1);
}
typedef int (*fun)(unsigned int, unsigned int);
int test1(const char *s, fun f, unsigned int a, unsigned int b) {
int y1 = ref(a, b);
int y2 = f(a, b);
if (y1 != y2) {
printf("%-10s %10u and %10u: ", s, a, b);
printf("ref %d ", y1);
printf("method %d\n", y2);
}
return y1 != y2;
}
int main(void) {
fun f[] = {method1, method2, method3, method_OP1, method_OP2, methodC};
char *s[] = {"method1", "method2", "method3", "method_OP1", "method_OP2",
"methodC"};
int fn = sizeof f / sizeof f[0];
unsigned u[] = {0, 1, 2, 3, //
UINT_MAX - 3, UINT_MAX - 2, UINT_MAX - 1, UINT_MAX};
int n = sizeof u / sizeof u[0];
for (int fi = 0; fi < fn; fi++) {
for (int ia = 0; ia < n; ia++) {
for (int ib = 0; ib < n; ib++) {
if (test1(s[fi], f[fi], u[ia], u[ib]) && 0) {
ia = n;
break;
}
}
}
}
}
method1 0 and 4294967295: ref 0 method 1
method1 4294967295 and 0: ref 0 method 1
method2 0 and 4294967295: ref 0 method 1
method2 4294967295 and 0: ref 0 method 1
method3 0 and 1: ref 1 method 0
method3 0 and 4294967295: ref 0 method 1
method3 1 and 2: ref 1 method 0
method3 2 and 3: ref 1 method 0
method3 4294967292 and 4294967293: ref 1 method 0
method3 4294967293 and 4294967294: ref 1 method 0
method3 4294967294 and 4294967295: ref 1 method 0
method_OP1 4294967294 and 4294967295: ref 1 method 0
method_OP1 4294967295 and 4294967294: ref 1 method 0
method_OP1 4294967295 and 4294967295: ref 1 method 0
method_OP2 4294967292 and 4294967292: ref 1 method 0
method_OP2 4294967292 and 4294967293: ref 1 method 0
method_OP2 4294967293 and 4294967292: ref 1 method 0
method_OP2 4294967293 and 4294967293: ref 1 method 0
method_OP2 4294967293 and 4294967294: ref 1 method 0
method_OP2 4294967294 and 4294967293: ref 1 method 0
method_OP2 4294967294 and 4294967294: ref 1 method 0
method_OP2 4294967294 and 4294967295: ref 1 method 0
method_OP2 4294967295 and 4294967294: ref 1 method 0
method_OP2 4294967295 and 4294967295: ref 1 method 0
(x - y + (y > x)) <= 1