推断某个值是否在某个范围是否在某个区间范围的代码是经经常使用到的,处理图片是否超出某个边界范围的时候。 我像素点设置为零。 否仅仅做点别的
在这个过程中, 我们可能要进行一次饱和处理, 于是乎写以下的代码:
if (val > 0 && val < 256) { // do something } else { // do something }
于是乎我就写了以下这样一个函数来讨论我们的问题
int32_t isRangAt1(int32_t val, int32_t min, int32_t max) { if (val > min && val < max) { return 1; } return 0; }这个函数非常easy, 就是推断一个value是否是在(min, max) 这个范围内,若果在返回1,否则0。 这里是用的是开区间
当然这里我没有考虑min < max 的容错处理;
这种代码好不好呢, 我们有没有别的实现方式呢, 当然有, 至少我们能够把if语句换成条件语句。例如以下:
int32_t isRangAt2(int32_t val, int32_t min, int32_t max) { return val <= min ? 0 : val > max ?当然我觉得是第二个实现比叫好(从反汇编的生成的指令看)。 可是可读性可能就差一些, 我们 还有第二种实现1 : 0; }
int32_t isRangAt3(int32_t val, int32_t min, int32_t max) { return (val > min) ^ (val > max); }以上三种实现功能上都是一个样的。 可是可读性递减, 效率应该是递增,
特别是第三种。 用了比較和异或运算实现的, 这样就消除了if语句的跳转, 从而提高效率
int32_t isRangAt4(int32_t val, int32_t min, int32_t max) { return (((uint32_t)(val - min)) >> 31) ^ (((uint32_t)(val - max)) >> 31); }
这也是汇编里面优化的一种策略, 当然这样的方法我開始我也想到能这么做。 我是通过放会变出来看出来的
这是四种方法的汇编(大家能够在ubutnu装一个交差编译工具, 这个汇编是powerpc 的)。 大家能够比較一下:
.section ".toc","aw" .section ".text" .align 2 .globl isRangAt1 .section ".opd","aw" .align 2 isRangAt1: .long .isRangAt1,.TOC.@tocbase32 .size isRangAt1,.-isRangAt1 .previous .type .isRangAt1,@function .globl .isRangAt1 .isRangAt1: .LFB11: cmpw 7,3,4 li 9,1 li 0,0 cmpw 6,3,5 ble 7,.L4 bge 6,.L8 .L5: mr 0,9 .L4: extsw 3,0 blr .L8: li 9,0 b .L5 .LFE11: .size .isRangAt1,.-.isRangAt1 .globl __gxx_personality_v0 .align 2 .globl isRangAt2 .section ".opd","aw" .align 2 isRangAt2: .long .isRangAt2,.TOC.@tocbase32 .size isRangAt2,.-isRangAt2 .previous .type .isRangAt2,@function .globl .isRangAt2 .isRangAt2: .LFB12: cmpw 7,3,4 li 9,1 li 0,0 cmpw 6,3,5 ble 7,.L12 ble 6,.L15 .L13: mr 0,9 .L12: extsw 3,0 blr .L15: li 9,0 b .L13 .LFE12: .size .isRangAt2,.-.isRangAt2 .align 2 .globl isRangAt3 .section ".opd","aw" .align 2 isRangAt3: .long .isRangAt3,.TOC.@tocbase32 .size isRangAt3,.-isRangAt3 .previous .type .isRangAt3,@function .globl .isRangAt3 .isRangAt3: .LFB13: cmpw 7,3,4 li 9,1 li 0,1 cmpw 6,3,5 bgt 7,.L17 li 0,0 .L17: bgt 6,.L18 li 9,0 .L18: xor 3,0,9 extsw 3,3 blr .LFE13: .size .isRangAt3,.-.isRangAt3 .align 2 .globl isRangAt4 .section ".opd","aw" .align 2 isRangAt4: .long .isRangAt4,.TOC.@tocbase32 .size isRangAt4,.-isRangAt4 .previous .type .isRangAt4,@function .globl .isRangAt4 .isRangAt4: .LFB14: subf 5,5,3 subf 3,4,3 xor 5,5,3 srwi 5,5,31 extsw 3,5 blr .LFE14: .size .isRangAt4,.-.isRangAt4 .ident "GCC: (GNU) 4.1.1 (SDK420, $Rev: 3547 $)"
比較一下大家会发现。前面三种实现差点儿没有一样, 当然这里我想说的一下。 这个汇编是我用gcc -O3出来的结果,大家都知道跳转语句比較耗时。 所以有时候我们要提高效率, 我们能够减少代码的可读性, 消除分支跳转, 跳过效率, 非常多时候。 编译器的一些优化策略是值得我们学习的。
这些汇编指令是powerpc ppu 的, 不了解的不要紧, 看看他们的生成的指令啥的即可。 了解了解。
有错欢迎指出, 分享请标明出处。 谢谢!
感觉好的话就顶一个, 感觉不错的话就踩一个。