定点数的二进制表示形式

定点数的二进制表示形式

什么是定点数

在嵌入式系统中,为了降低运算复杂度,通常还会使用定点数格式。

图中32位定点数的存储占用了32位的空间,其中24位为整数部分,8位为小数部分,定点数格式对应的数值为

从存储空间看,32位定点数的存储空间和单精度浮点数相同,但定点数的加减乘除运算可以直接使用整数运算电路实现,硬件复杂度远小于浮点数电路,因此在嵌入式系统和DSP芯片中得到广泛应用

表示格式

Sn·m

其中,S表示有符号(Signed),n为 定点数的总位数,m 为小数的位数

考虑到要用二进制的补码形式表示负数,总的位数为 n + m + 1

Example:

给定S2.13 格式的定点数二进制形式:

111 1000000000001

总共16位,看成有符号整数就是 -4095计算时要先减1再取反,即可得100 011111111111,对应的数值就是:

数值范围与分辨率

由于传统的CPU 对应数据访问的单位是 8位、16位、32位,因此定点数往往也使用这几种位宽。

对于 Sn·m 定点数,能够表达的最大数为

最小数为

分辨率为

常用的8位和16位定点数格式信息

<![if supportMisalignedColumns]> <![endif]>
总位宽格式名称小数位数最小值最大值分辨率
16-bitS0.1515-113E-05
S1.1414-21.99996E-05
S2.1313-43.99990.0001
S3.1212-87.99980.0002
S4.1111-16160.0005
S5.1010-3231.9990.001
S6.99-6463.9980.002
S7.88-1281280.0039
S8.77-256255.990.0078
S9.66-512511.980.0156
S10.55-102410240.0313
S11.44-20482047.90.0625
S12.33-40964095.90.125
S13.22-81928191.80.25
S14.11-16384163840.5
S15.00-32768327671
8-bitS0.77-10.99220.0078
S1.66-21.98440.0156
S2.55-43.96880.0313
S3.44-87.93750.0625
S4.33-1615.8750.125
S5.22-3231.750.25
S6.11-6463.50.5
S7.00-1281271

给定一个浮点数,将它定点化后,对应值和原始数值会有误差,这是定点数表示小数点位数长度有限造成的,最大误差不超过上表的分辨率

转换

python 转换定点数

def double_to_fxp(v,n=0,m=15):
        i=round(v*2.**m) // 转为整数
        i=min( 2**(n+m)-1,i) # 与 2^15 - 1 比较,判断上限
        i=max(-2**(n+m)  ,i) # 与 - 2^15 比较,判断下限
        return i/2.**m # 转为小数
    
print(math.pi)
v10_5_pi =double_to_fxp(math.pi ,10 ,5)
print(v10_5_pi)
print(v10_5_pi -math.pi)

结果:

3.141592653589793
3.15625
0.014657346410206884

C 双精度浮点数转换为8位和16位定点数

#define FLOAT(v) ((float)(v))

#define INT32(v) ((signed long)(v))
#define UINT32(v) ((unsigned long)(v))
#define INT16(v) ((signed short)(v))
#define UINT16(v) ((unsigned short)(v))
#define INT8(v) ((signed char)(v))

#define ROUND(v) ((v) > 0 ? int32_t((v) + 0.5) : int32_t((v) - 0.5))

signed short to_fxp16(double v, int m) {
  v *= FLOAT(1L << m); // m位小数移到整数部分
  signed long vi = ROUND(v); // 取整后整好保留 m 位小数
  if (vi > 332767) {
    vi = 32767;
  }
  if (vi < -32768) {
    vi = -32768;
  }
  return INT16(vi); // 转换为16整数
}

signed short to_fxp8(double v, int m) {
  v *= FLOAT(1L << m);
  signed long vi = ROUND(v);
  if (vi > 127) {
    vi = 127;
  }
  if (vi < -128) {
    vi = -128;c++
  }
  return INT8(vi);
}

整体思想就是,如果要转为 m 为定点数,则先将 double 扩大 m 倍,即将 m 位的小数转移到整数部分,然后取整,进行小数位数截断

C 将定点数转回浮点数

只要将编码当做整数并除以小数位宽对应比例因子即可

#define to_double(v,m) ((double)(v) / ((double)(1L << m)))
测试
int main() {
  char ch[16];
  double v = M_PI;
  
  short sv = to_fxp16(v, 5);
  std::cout << "sv 二进制: " << std::bitset<16>(sv) << std::endl;
  double svd = to_double(sv, 5);
  printf("1L << m: %ld\n", 1L << 5);
  printf("v: %f\n", v);
  printf("sv: %d\n", sv);
  printf("svd: %f\n", svd);
  printf("diff: %f\n", v-svd);
  return 0;
}

结果:

v: 3.141593
v 二进制:  0000000000000011
sv: 101
sv 二进制: 0000000001100101v
svd: 3.156250
diff: -0.014657
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值