一般情况下,如果要我们写一个求绝对值的函数,我们的实现很有可能会是这样:

templateT abs_Normal(T tNum)

{if(tNum>0.0)returntNum;elsereturn-tNum;

}

也就是说我们会用到一个if-else判断来决定是否反转符号位。在3D游戏软件,或一些对性能要求比较高的底层系统中,当大规模的求绝对值时,这个if-else结构会带来性能上的损失,那么,如何来消除if-else结构呢?或许会有人说,我们可以用三元操作符啊:

templateT abs_Normal(T tNum)

{returntNum>0.0?tNum :-tNum;

}

但是事实上这是换汤不换药,因为其实质上还是存在if-else的判断的(这应该可以从反汇编代码中看出来)。

我们是通过位操作来消除if-else判断来求绝对值。

因为使用位操作,我们不得不考虑我们操作对象类型的字节数,下面我将以都是4字节得float和int为例实现位操作求绝对值。

首先,我们有必要了解一下float与int在计算机中的内部表示方法。

1) float: float即单精度浮点数,"浮点数"由两部分组成,即尾数和阶码。在浮点表示方法中,小数点的位置是浮动的,阶码可取不同的数值。为了便于计算机中小数点的表示,规定将浮点数写成规格化的形式,即尾数的绝对值大于等于0.1并且小于1,从而唯一规定了小数点的位置。尾数的长度将影响数的精度,其符号将决定数的符号。浮点数的阶码相当于数学中的指数,其大小将决定数的表示范围。一个浮点数在计算机中的表现形式如下:

尾数符号 阶码 尾数有效值

2) int: 用补码表示,因为正整数的原码,反码,补码都是一样的,而负整数的补码则是通过原码->反码->补码转换来的,所以,-3与3的内部表示位差别不仅仅在符号位

其次,这里先列出两个在代码中用到的宏:

#define INV_SIGN_BIT 0x7fffffff //用来反转符号位

#define USE_ASM         //是否使用汇编代码

1 float求绝对值

知道了float的内部表示,我们知道要求其绝对值,只要将其尾数符号位置0即可。这又有下面两种方法:

1)与:通过和INV_SIGN_BIT相"与"而将符号位置0

inlinefloatFabs_and(floatfNum)

{

#ifdef USE_ASMfloatfOut;

__asm

{

MOV EAX, fNum;

AND EAX, INV_SIGN_BIT;//set the sign bit to 0 by ANDMOV fOut, EAX;

}returnfOut;#elseint*temp=(int*)&fNum;intout=*temp&INV_SIGN_BIT;return*((float*)&out);#endif}

注:

1)这里将float转化成int的原因是C语言不支持float的移位操作。

2)移位:通过先逻辑左移1位,再逻辑右移一位将符号位置0

inlinefloatFabs_shift(floatfNum)

{

#ifdef USE_ASMfloatfOut=0;

__asm

{

MOV EAX, fNum;

SHL EAX,1;//set the sign bit to 0 by shift left then rightSHR EAX,1;

MOV fOut, EAX;

}returnfOut;#elseunsignedint*temp=(unsignedint*)&fNum;

unsignedintout=*temp;out=out<<1;out=out>>1;return*((float*)&out);#endif}

注:

1)这里使用unsigned int的原因是C语言的移位操作对有符号数是算术移位,对无符号数是逻辑移位。而我们需要的是逻辑移位

2 int求绝对值

因为整型的内部表示是反码,我们不能简单的通过符号位置0求绝对值,下面的算法很好的解决了这个问题:

inlineintAbs_bit(intiNum )

{

#ifdef USE_ASMintiOut=0;

__asm

{

MOV EAX, iNum;

MOV EDX, EAX;

SAR EDX,31;//all of edx's bit are eax's sign bit: 000.. or 111

XOR EAX, EDX;//this interesting algorithm help to avoid "if else" structureSUB EAX, EDX;

MOV iOut, EAX;

}returniOut;#elseintout=iNum;inttemp=iNum;

temp=temp>>31;out=out^temp;out=out-temp;returnout;#endif}

注:

1)对于代码

temp = temp >> 31;

out = out ^ temp;

out = out - temp;

如果iNum是正数:

temp = temp >> 31; //temp = 0

out = out ^ temp; //与0异或不变

out = out - temp; //减0不变

out的结果就是iNum,即正数的绝对值是其本身,没问题

如果iNum是负数:

temp = temp >> 31; //temp = oxffffffff

out = out ^ temp; //out为iNum求反

out = out - temp; // 此时temp = 0xffffffff = -1, 所以out = out + 1

把一个负数的补码连符号位求反后再加1,就是其绝对值了。比如对于-2来说:原码

反码

补码

补码全求反

再加1

备注

10000010

11111101

11111110

00000001

00000010

大家可以看到第一个与最后一个数只有符号位不同,也就实现了求其绝对值。

对于其他类型的数据求绝对值,应该 都是大同小异的。这里就不再列举。

posted on 2007-07-05 17:56 SmartPtr 阅读(7323) 评论(13)  编辑 收藏 引用

if用法求绝对值c语言,用位运算实现求绝对值-有效避开if-else判断相关推荐

  1. c语言中用if语句计算两数之差的绝对值,用位运算实现求绝对值-有效避开if-else判断...

    用位运算实现求绝对值-有效避开if-else判断 By SmartPtr(http://www.cppblog.com/SmartPtr/) 一般情况下,如果要我们写一个求绝对值的函数,我们的实现很有 ...

  2. C语言截取整数的某些位编程,C语言中位运算的巧用(转)

    一 .位运算实例 1.用一个表达式,判断一个数X是否是2的N次方(2,4,8,16.....),不可用循环语句. X:2,4,8,16转化成二进制是10,100,1000,10000.如果减1则变成0 ...

  3. c语言程序设计施莹答案,C语言课件-位运算.ppt

    C语言课件-位运算.ppt C语言程序设计,信息工程学院 施莹 2019年11月,第12章 位运算,C语言是为描述系统而设计的,其功能应当具有汇编的功能 故C语言具有高级语言的的功能,也肯定低级语言的 ...

  4. 谭浩强c语言不讲位运算呢,谭浩强C语言_CHAR12位运算.DOC

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbspC/C++资料 谭浩强C语言_CHAR12位运算.DOC11页 ...

  5. c语言 枚举,位运算

    c语言 枚举,位运算 枚举 枚举类型的定义和枚举变量的说明 一.枚举的定义枚举类型定义的一般形式为 二.枚举变量的说明 枚举类型变量的赋值和使用 位运算 位域 一.位域的定义和位域变量的说明 二.位域 ...

  6. 单片机c语言位运算写法,单片机与嵌入式系统中C语言的位运算小记

    原标题:单片机与嵌入式系统中C语言的位运算小记 编了个PIC的项目,对里的还是蛮有感悟的,特此记录一下. 譬如说,在程序中定义了一个char类型的变量, purge_short_enable_flag ...

  7. C语言基础位运算符号

    C语言基础位运算符号 1.<< 左移 00011000 << 3 = 11000000(便携的赋值方法:<<=) 2.>> 右移 00100100 &g ...

  8. 用C语言编码定积分,C语言__用六种方法求定积分C语言__用六种方法求定积分.doc...

    C语言__用六种方法求定积分C语言__用六种方法求定积分 描述问题 利用①左矩形公式,②中矩形公式,③右矩形公式 ,④梯形公式,⑤simpson公式,⑥Gauss积分公式求解定积分. 分析问题 2.1 ...

  9. c语言中位运算之布尔运算

    c语言中位运算中的布尔运算有:&.|.~.^ &:按位与 |:按位或 ~:按位非 ^:按位异或,相同为0,相异为1. 计算规则如下: 位的逻辑运算的作用: 使用位向量做集合编码: 使用 ...

最新文章

  1. 翻译:Single Sign-On for Everyone
  2. View工作原理(二)导致View重建原因
  3. k2pdfopt教程
  4. mysql递归查询树,帮你突破瓶颈
  5. JavaScript 预解析机制
  6. eigen 编译_四足机器人优化方法:Webots下Eigen与qpOASES非线性优化库环境搭建
  7. TCP/IP、HTTP、HTTPS
  8. 计算机科学导论论文文章,计算机科学导论论文参考文献集 计算机科学导论论文参考文献数量是多少...
  9. SVG defs元素
  10. 总结一下自己的大学四年
  11. Window10总是自动打开网络代理的解决方案法
  12. 嵌入式开发学习路线图
  13. 怎么理解PKW和PZD,各有什么作用
  14. 【渝粤题库】陕西师范大学292011 初级微观经济学 作业(高起专)
  15. SpringBoot整合RabbitMQ
  16. java 类继承命名_Java oop 代码7:A1,A2继承A且B1,B1继承B且A,B继承C的商品类,人物模型类两道题...
  17. 【原创】Quartus II 简单设计流程
  18. 服装智能供应链管理系统和企业以需要为导向
  19. 计算机维修进度安排表,教学进度表实验安排表考勤成绩册计算机网络技术教学进度表(计09本).doc...
  20. 画法几何3---- 基本几何体的投影

热门文章

  1. c语言数据库的连接字符串函数,C语言strcat()函数:连接字符串
  2. C语言if条件表达式只能是,小白基础知识必备|| 条件表达式
  3. (精华2020年5月4日更新) vue教程篇 v-for的使用
  4. Power map(绘图渲染工具)
  5. nginx下载文件超时
  6. 中南计算机在线考试答案,中南大学计算机基础在线考试(含答案).docx
  7. 2021年材料员-通用基础(材料员)模拟考试题及材料员-通用基础(材料员)模拟考试系统
  8. DevOps敏捷开发流程
  9. java语言的主要用途_java主要是做什么的?
  10. uniapp 实现PDA设备的扫码功能 超级详细篇