c语言带符号位的二进制数组,二进制数据的表示与运算(有符号、无符号数数学运算以及Q格式定点精度问题)...

2023-05-16

本文介绍了二进制binary数据在存储器的表示方式,C语言的位运算符号,有符号和无符号混合运算的规则,主要是乘法和除法规则不同。最后以IIR滤波器定点实现的例子来说明如何提高计算精度。

二进制数据与补码、原码和反码表示以及位运算

位运算是指二进制位的运算,在系统软件中,经常要处理一些二进制位的问题,如设置标志位,进行标志位的检测,通常见于状态寄存器和控制寄存器的访问,位运算的类型有相与,与非,相或,或非,异或,同或,取反等操作。

C语言的位运算

运算符含义描述

&按位与如果两个相应的二进制位都为1,则该位的结果值为1,否则为0

|按位或两个相应的二进制位中只要有一个为1,该位的结果值为1

^按位异或若参加运算的两个二进制位值相同则为0,否则为1

~取反一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0

<

>>右移将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0;对于有符号数据,逻辑右移则高位补零,算术右移则高位填充符号位;

二进制的存储表示方法

计算机中的存储器就是由许多字节(byte)单元组成的。一般,内存的最小度量单位就叫做位(bit),也叫比特。而一个字节就是由8个二进制位组成,其中,最右边的一位叫做最低位LSB,最左边的一位叫做最高位MSB。所以,一个16位的整数将在内存中占据2个字节的存储空间,一个32位的整数类型占据4个字节的存储空间。数据有原码、反码、补码3种表示形式。

原码

原码是指将最高位作为符号位(0表示正,1表示负),其它数字位代表数值本身的绝对值的数字表示方式。以8比特的数据为例,原码00000110表示数字6,而原码10000110表示数字-6,其中的第一位为符号位,0表示正数,1表示负数。

反码

反码表示规则为:如果是正数,则表示方法和原码一样;如果是负数,则保留符号位1,然后将这个数字的原码按照每位取反,则得到这个数字的反码表示形式。同样以8位的系统为例,数字6的反码也就是它的原码:00000110,而数字-6的反码为1111 1001,即为数字6与1111 1111的按位异或的结果。

补码补码是计算机表示数据的一般方式,其规则为:如果是整数,则表示方法和原码一样;如果是负数,则将数字的反码加上1(相当于将原码数值位取反然后在最低位加1)。同样以8位的系统为例,数字6的补码也就是它的原码:00000110,而数字-6的补码为11111010;有符号数和无符号数运算

需要说明的是,计算机通常的处理都是按照补码数据进行的,以下的所有二进制数据的表示都是补码表示。通常的有符号和无符号数据的说法都源于高级语言如C语言的数据表示形式,对于在内存里的数据补码表示而言,对于同样的二进制码,如8比特的数据11111010,它可以是数字-6的补码,也可以是(0000 0000) 11111010即+250的补码形式。而把该内存区域的数据读到寄存器里,可以根据数据加载类型来决定是否进行符号扩展还是零扩展,即由具体的加载指令来区分内存数据的类型,当然除了数据加载,对于数据运算而言,也是存在两套的汇编指令来告诉具体的操作类型是有符号的还是无符号的运算,如TIDSP中常见的ADD和ADDU,MPY和MPYU指令分别针对有符号数据和无符号数据运算的。而高级语言引入的有符号和无符号的表示都是为了引导编译器把代码汇编成正确的汇编指令。

一个引导编译器的C语言例子

#include

#include

intmain()

{

int x= 2;

char *str = "abcd";

int y= (x - strlen(str) ) / 2;

printf("%d/n",y);

}

结果应该是-1 但是却得到:2147483647。为什么?因为strlen的返回值,类型是size_t,也就是unsigned int,与int 混合计算时有符号类型被自动转换成了无符号类型,结果为无符号数据,观察编译后的代码,除法指令为div,意味无符号除法。解决办法就是强制转换,变成 int y = (int)(x - strlen(str) ) / 2;强制向有符号方向转换(编译器默认正好相反),这样一来,除法指令编译成 idiv 了。

C语言中有符号/无符号数混合运算操作数全为有符号数,则计算过程中和计算结果全部按照有符号运算;

操作数全为无符号数,则计算过程中和计算结果全部按照无符号运算;

操作数混合了有符号数、无符号数,则操作数中存在至少一个无符号数,则所有操作数都被转化为无符号数,运算操作也采用相应的无符号操作符进行,计算完的结果也是一个无符号数;

举例:

(unsigned int)a / (signed int)b会采用无符号除法进行,其实质相当于(unsigned int)a / (unsignedint)b,计算结果也是一个无符号数。再进一步,对于运算-2 /-1,如果采用有符号数运算,结果是1,采用无符号数运算,结果则是0。所以 (signed int)(-2) / (unsignedint)(-1)的结果就是0了。

汇编有符号和无符号乘法差别有符号乘法规则:数据的绝对值相乘,符号位异或,如果需要高位扩展符号位则扩展符号位;

无符号乘法规则,按位乘并累加。

以上面的8位的定点数据乘法为例,对于无符号乘法,即为250U*6U=1500U,而-6S*6S=-36S。

11111010U 1111 1010S

X X

00000110U 0000 0110S

00000101 1101 1100U 1111 1111 1101 1100S

IIR滤波器定点算法提高精度(以TI的DSP为例)对输入的数据norm后进行乘法,然后再计算乘法,然后累加,如果对于分阶段的,可以对若干个一起求出共同的norm值,然后计算乘法,累加完成后denorm回去。

中间累加结果为40bit,利用40位的累加器,同时还可以考虑SHRMB,SHLMB以及40-bit的SAT指令等;

Reference:

本文介绍了二进制binary数据在存储器的表示方式,C语言的位运算符号,有符号和无符号混合运算的规则,主要是乘法和除法规则不同。最后以IIR滤波器定点实现的例子来说明如何提高计算精度

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c语言带符号位的二进制数组,二进制数据的表示与运算(有符号、无符号数数学运算以及Q格式定点精度问题)... 的相关文章

随机推荐