判断某个值是否在某个范围是否在某个区间范围的代码是经常用到的,处理图片是否超出某个边界范围的时候, 我像素点设置为零, 否只做点别的
在这个过程中, 我们可能要进行一次饱和处理, 于是乎写下面的代码:
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;
}
这个函数很简单, 就是判断一个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 的, 不了解的不要紧, 看看他们的生成的指令啥的就行, 了解了解。
有错欢迎指出, 分享请标明出处, 谢谢!
感觉好的话就顶一个, 感觉不错的话就踩一个。