如何在无符号 N 位交互器中修复二进制点的位置

How to fix the position of binary point in an unsigned N-bit interger?

本文关键字:二进制 位置 无符号 交互      更新时间:2023-10-16

我正在努力开发一种C++定点算法。我知道,对于 N 位整数,定点二进制整数表示为 U(a,b(。例如,对于一个 8 位整数(即 256 个样本(,如果我们以 U(6,2( 的形式表示它,这意味着二进制点位于从形式右侧开始的第 2 位的左侧:

                   b5 b4 b3 b2 b1 b0 . b(-1) b(-2)

因此,它有6个整数位和2个小数位。在C++中,我知道我可以使用一些位移运算符,但它们基本上用于移动输入流的位,我的问题是,如何定义形式的二进制不动点整数,fix<6,2>或U(6,2(。所有主要的处理操作都将在小数部分进行,我只是在C++中找到一种进行此修复的方法。任何有关这方面的帮助将不胜感激。谢谢!

示例:假设我有一个在x轴上有1024个采样点的输入离散信号(现在只是认为这个输入信号来自某个传感器(。每个采样点都有一个特定的振幅。假设时间 2(x 轴(的样本振幅为 3.67(y 轴(。现在我有一个变量"int *input;",它取样本 2,二进制为 0000 0100。所以基本上我想通过在 C++ 中对样本 2 执行 U(5,3( 来将其设为 00000.100。这样我就可以对输入采样周期或时间的分数执行插值操作。

PS - 我不想为此创建一个单独的类或使用外部库。我只想从输入信号中获取每 8 位,对其执行 U(a,b( 修复,然后在小数部分完成其余操作。

简短的回答:左移。

长答案:

  1. 定点数存储为整数,通常int,这是特定平台最快的整数类型。

  2. 没有小数位的普通整数通常称为Q0Q.0QX.0其中X是底层存储类型(通常为int(的总位数。

  3. 要在不同的Q.X格式之间进行转换,请左移或右移。例如,要将 5 in Q0转换为 Q4 中的 5,请将其左移 4 位,或乘以 16。

  4. 通常,查找或编写一个执行基本计算的小型定点库很有用,例如a*b>>q(a<<q)/b。因为您将做很多Q.X=Q.Y*Q.ZQ.X=Q.Y/Q.Z,并且在进行计算时需要转换格式。您可能已经观察到,使用普通*运算符会给你Q.(X+Y)=Q.X*Q.Y,所以为了将结果适合Q.Z格式,你需要将结果右移 (X+Y-Z) 位。

  5. 除法是类似的,你得到Q.(X-Y)=Q.X*Q.Y从标准/运算符,并且为了得到Q.Z格式的结果,你在除法之前移动除法。不同的是,除法是一项昂贵的操作,从头开始编写一个快速的操作并非易事。
  6. 请注意平台的双字支持,这将使您的生活更轻松。使用双字算术,a*b的结果可以是 ab 大小的两倍,这样您就不会因为执行a*b>>c而丢失范围。如果没有双字,您必须限制ab的输入范围,以便a*b不会溢出。当你第一次开始时,这并不明显,但很快你会发现你需要更多的分数位或愤怒来完成工作,你最终需要深入研究处理器ISA的参考手册。

例:

float a = 0.1;// 0.1
int aQ16 = a*65536;// 0.1 in Q16 format
int bQ16 = 4<<16// 4Q16
int cQ16 = a*b>>16 // result = 0.399963378906250Q16 = 26212, 
                   // not 0.4Q16 = 26214 because of truncating error

如果这是您的问题:

问:我是否应该将定点整数定义为模板,U<int a, int b>(int number) U(int a, int b)

我认为你的答案是:"你想定义采用两个固定二进制点整数的运算符吗?如果是这样,请将它们作为模板。

如果不定义运算符,则模板只是稍微复杂一些。所以我把它排除在外。

但是,如果您要定义运算符,则不希望能够添加U<4, 4>U<6, 2>。你会把你的结果定义为什么?如果您尝试这样做,模板会给您一个编译时错误。