繁体   English   中英

词典的整数比较

[英]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但是它更具可移植性。
我的机器上速度的差异可以忽略不计(第二个速度快__builtin_clz %),但是在没有__builtin_clz作为一个处理器指令的机器(例如x86上的BSR)上,该差异可能会很大。

这是计算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": %d\n",
        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 == 0的情况下是不正确的。 除非b == 0 ,否则它应该返回true,但是由于tmp & a将为false而不考虑tmp的值(它将是b中的最低位1位),因此该函数将返回false。

如果满足以下条件,则a应该小于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 ))。

考虑到我们在tmpa^b的最低位的事实,对情况“ ab的适当前缀” a简单测试是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. 这是值得做的,因为(1)即使__builtin_clz是内置的,它也不一定超快; (2)如果您使用的不是gcc或clang编译器,则可能不存在。

  2. 如果tmp是无符号类型,即使基本实现不是2s-complement, -tmp也可以保证是tmp的2s-complement负数。 请参见§6.2.6.2/ 1(对于某些整数N,无符号类型的范围是0..2 N -1)和&6.3.1.3 / 2(通过重复加2将负值转换为无符号整数类型) N,直到该值在范围内。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM