• 「工具箱」Bit Hacks


    昨晚看到的博客,Peteris Krumins 谈到了个人工具箱的重要性。比较有启发。

    既然目前的个人知识储备以及实践经验,还比较不成系统,那就一点点开始,慢慢来好了。

    第一篇,就以昨天看到的这篇 Bit Hacks 起始。原理部分不多做解释,如果熟悉二进制补码形式的数位表示方法,就可以轻松理解。如下是我写的头文件(省略了头部注释),与上述链接中的实现有些不同,下文将会详细阐述。

    #ifndef BIT_HACKS_H_

    #define BIT_HACKS_H_

    // Convert $bnumber to int.
    // i.e. "101" to 5, "011" to 3 etc..
    int strtob(char *bnumber);

    // x is an even or odd number?
    #define B_EVEN(x) ((((x) & 0x1) == 0) ? 1:0)
    #define B_ODD(x) (!B_EVEN(x))

    // n-th bit is set?
    #define B_IS_SET(x, n) (((x) & (1<<(n))) ? 1:0)

    // set or unset n-th bit.
    #define B_SET(x, n) ((x) | (1<<(n)))
    #define B_UNSET(x, n) ((x) & ~(1<<(n)))

    // toggle n-th bit.
    #define B_TOGGLE(x, n) ((x) ^ (1<<(n)))

    // turn off rightmost 1-bit.
    #define B_TURNOFF_1(x) ((x) & ((x)-1))

    // turn on rightmost 0-bit.
    #define B_TURNON_0(x) ((x) | ((x)+1))

    // isolate rightmost 1-bit, i.e. set it, and unset the others.
    #define B_ISOLATE_1(x) ((x) & ~((x)-1))

    // isolate rightmost 0-bit.
    #define B_ISOLATE_0(x) (~(x) & ((x)+1))

    // propagate the rightmost 1, i.e. 2#00100 to 2#00111.
    #define B_PROPAGATE_1(x) ((x) | ((x)-1))

    #endif /* BIT_HACKS_H_ */

    我这里的实现方式,同原文作者的实现方式不太一样。主要是两点。

    • 所有宏都没有「副作用」。原文作者的某些宏定义,对宏参数本身做了修改;而这里的每一个宏,只是一个纯粹的求值表达式,没有赋值过程。
    • 对于 B_ISOLATE_1(x) 的实现,原文作者使用了取负值的方法,不太容易理解,我这里使用了类似 B_TURNOFF_1(x) 的减一操作,个人觉得从比特位的角度来理解,更清晰一些。

    作者在其后的一篇博客中,实现了这个头文件,并做了测试。然而其实现的一个部分,我不太赞同。即,如何很直观的从二进制数位表示法,生成一个十进制数?作者的方法如下。

    #define HEXIFY(X) 0x##X##LU

    #define B8IFY(Y) (((Y&0x0000000FLU)?1:0) + \
    ((Y&0x000000F0LU)?2:0) + \
    ((Y&0x00000F00LU)?4:0) + \
    ((Y&0x0000F000LU)?8:0) + \
    ((Y&0x000F0000LU)?16:0) + \
    ((Y&0x00F00000LU)?32:0) + \
    ((Y&0x0F000000LU)?64:0) + \
    ((Y&0xF0000000LU)?128:0))

    #define B8(Z) ((unsigned char)B8IFY(HEXIFY(Z)))

    这里的写法,是将诸如 10111100 的字符串当成一个 16 进制的无符号长整型处理,由 0x##X##LU 所完成。然后,再通过分别 B8IFY(Y) 宏完成十进制计算。

    作者认为这是很机巧的一个做法,并对最初发明此写法的 Tom Torfs 表示感谢。然而我却觉得,这个写法比较糟糕。原因在于,长整型能够表示的数值范围大小有限,16 进制的 1 0 组合,未免过于浪费。正因如此,作者的例子都是在 B8 即 8 位比特范围内完成。然而,这里的 Bit Hacks 是通用的,只要数字以二进制补码形式表示,都能如是处理。

    对于这个问题,我采取了字符串的方式,即上述头文件里的 int strtob(char *bnumber); 函数。实现也很简单,不再列出。

    最后提一下作者另一个宏技巧,就是 # 符号,可以将某个宏参数变成字符串。值得借鉴。我利用这个特性写了个 run 宏。

    // test_func : int (*test_func)(void);
    #define run(test_func) \
    do { \
    int result = (test_func)(); \
    if (result && verbosity == With_Function_Name) \
    printf("Passed: %s\n", #test_func); \
    else if (result) \
    printf("."); \
    } while (0)

    - EOF -

  • 相关阅读:
    POJ 题目2750 Potted Flower(线段树求环型区间中连续区间的最大和)
    即使没人看我们也要坚持写Blog
    鸟哥的Linux私房菜-----7、硬件管理
    android createbitmap函数内存溢出,求解怎样进行处理out of memory溢出问题
    hdu4614Vases and Flowers 线段树
    安装npm及cnpm(Windows)
    安装npm及cnpm(Windows)
    安装npm及cnpm(Windows)
    Echarts设置点击事件
    Vs Code中炫酷写代码插件Power Mode的安装配置
  • 原文地址:https://www.cnblogs.com/jtuki/p/toolbox_bit_hacks.html
Copyright © 2020-2023  润新知