如何确定无符号 N 位整数中二进制小数点的位置?

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

我正在使用 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++ 中进行此修复的方法。关于此的任何帮助将是 appreciated.Thanks!

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

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

简答:左移。

长答案:

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

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

  3. 要在不同的 Q.X 格式之间转换,左移或右移。例如,要将Q0中的5转换为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 溢出。这在您刚开始时并不明显,但很快您就会发现您需要更多的小数位或 rage 才能完成工作,您最终将需要深入研究您处理器的 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>。你会将你的结果定义为什么?如果您尝试这样做,模板会给您一个编译时错误。