整数的词法比较
Lexicographical comparison of integers
我想用字典法比较两个小(<=20)整数集(1..20)。
集合由单个整数表示,例如
1、2、4、6
将表示为
... 0 1 0 1 0 1 1
(... 7 6 5 4 3 2 1)
所以在有1的地方,这个数字就存在于集合中。
有人能验证一下这个代码是否正确吗?
bool less_than(unsigned a, unsigned b) {
unsigned tmp = a ^ b;
tmp = tmp & (~tmp + 1); //first difference isolated
return (tmp & a) && (__builtin_clz(b) < __builtin_clz(tmp));
}
__builtin_clz
部分用于当b
是a
的前缀时的情况
空集的情况在其他地方处理(__builtin_clz
对于0是未定义的)。
编辑:
bool less_than(unsigned a, unsigned b) {
unsigned tmp = a ^ b;
tmp &= -tmp; //first difference isolated
return ((tmp & a) && (__builtin_clz(b) < __builtin_clz(tmp)))
|| (__builtin_clz(a) > __builtin_clz(tmp));
}
和
bool less_than_better(unsigned a, unsigned b) {
unsigned tmp = a ^ b;
tmp &= -tmp; //first difference isolated
return ((tmp & a) && tmp < b) || tmp > a;
}
似乎两者都是正确的。(在数千万次随机测试中,与使用std::lexicographical_compare
的天真实现相比进行了测试)
第二个更便携,因为它不使用__builtin_clz
我的机器上的速度差异可以忽略不计(第二个速度快约2%),但在没有__builtin_clz
作为一个处理器指令的机器上(例如x86上的BSR),差异可能会很大。
在a == 0
。除非b == 0
,否则应返回true,但由于无论tmp
的值(它将是b中的最低阶1位)如何,tmp & a
都将为false,因此函数将返回false。
CCD_ 12应该是"0";小于";b
如果:
1. `a` is a proper prefix of `b`, or
2. The lowest-order bit of `a^b` is in `a`.
第一个条件还处理a
是空集而b
不是的情况。(这与您的公式略有不同,即"(a^b
的最低阶位在a
中)而不是(b
是a
的适当前缀)。)
一个简单的测试案例";CCD_ 20是CCD_;,假定我们在tmp
中具有a^b
的最低阶比特的事实是tmp > a
。这就避免了__builtin_clz
的使用[注1]。
另外,你可以写
tmp = tmp & (~tmp + 1);
作为
tmp &= -tmp;
但我认为大多数C编译器都会自己找到这种优化。[注2]。
应用这些优化,结果将是(未经测试的):
bool less_than(unsigned a, unsigned b) {
unsigned tmp = a ^ b;
tmp &= -tmp; //first difference isolated
return tmp > a || tmp & a;
}
备注
这是值得做的,因为(1)即使
__builtin_clz
是内置的,它也不一定是超快的;(2)如果使用gcc或clang以外的编译器进行编译,则可能不存在它。如果
tmp
是无符号类型,即使底层实现不是2s补码,-tmp
也保证是tmp
的2s补数负数。参见§6.2.6.2/1(对于某个整数N,无符号类型的范围为0..2N-1)和&6.3.1.3/2(通过重复添加2N将负值转换为无符号整数类型,直到该值在范围内。
以下是计算2位输入的所有组合的列表:
#include <stdio.h>
bool less_than(unsigned a, unsigned b) {
unsigned tmp = a ^ b;
tmp = tmp & (~tmp + 1); //first difference isolated
return (tmp & a) && (__builtin_clz(b) < __builtin_clz(tmp));
}
#define BITPATTERN "%d%d%d"
#define BYTETOBITS(byte)
(byte & 0x04 ? 1 : 0),
(byte & 0x02 ? 1 : 0),
(byte & 0x01 ? 1 : 0)
int main(int argc, char** argv) {
for ( int a = 0; a < 4; a ++ )
for ( int b = 0; b < 4; b ++)
printf("a: "BITPATTERN" b: "BITPATTERN": %dn",
BYTETOBITS(a), BYTETOBITS(b), less_than(a,b)
);
}
这是输出:
a: 000 b: 000: 0
a: 000 b: 001: 0
a: 000 b: 010: 0
a: 000 b: 011: 0
a: 001 b: 000: 0
a: 001 b: 001: 0
a: 001 b: 010: 1
a: 001 b: 011: 0
a: 010 b: 000: 0
a: 010 b: 001: 0
a: 010 b: 010: 0
a: 010 b: 011: 0
a: 011 b: 000: 0
a: 011 b: 001: 0
a: 011 b: 010: 1
a: 011 b: 011: 0
看起来不太对劲。。
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么比较运算符如此快速
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 比较字符数组
- 将模板化的类型与C++中的某些类/类型进行比较
- C++自定义比较函数
- 如何比较自定义类的std::变体
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- std::设置自定义比较器
- 布尔比较运算符是如何在C++中工作的
- C++将目录中的所有文件与::filesystem进行比较
- shell排序中的交换和比较
- 如何在C++中比较两个char数组
- catch框架有没有办法比较流或文件
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 智能指针作为无序映射键,并通过引用进行比较
- 比较if语句中的数组值和int值
- 对于循环变体比较
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 整数的词法比较