如何确定无符号 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) 修复,然后其余操作在小数部分完成。
简答:左移。
长答案:
定点数存储为整数,通常是 int
,这是特定平台最快的整数类型。
没有小数位的普通整数通常称为Q0
、Q.0
或QX.0
,其中X是底层存储类型的总位数(通常是int
).
要在不同的 Q.X
格式之间转换,左移或右移。例如,要将Q0
中的5转换为Q4中的5,将其左移4位,或乘以16。
通常查找或编写一个小型定点库来执行基本计算很有用,例如 a*b>>q
和 (a<<q)/b
。因为你会做很多Q.X=Q.Y*Q.Z
和Q.X=Q.Y/Q.Z
,在做计算的时候需要转换格式。正如您可能已经观察到的,使用普通的 *
运算符将得到 Q.(X+Y)=Q.X*Q.Y
,因此为了使结果适合 Q.Z
格式,您需要将结果右移 (X+Y-Z)
] 位。
- 除法类似,您从标准
/
运算符中得到 Q.(X-Y)=Q.X*Q.Y
,要获得 Q.Z
格式的结果,您需要在除法之前移动被除数。不同的是,除法是一个昂贵的操作,从头开始写一个快速的操作并不简单。
- 注意您平台的双字支持,这会让您的生活更轻松。使用双字运算,
a*b
的结果可以是 a
或 b
大小的两倍,这样您就不会因执行 a*b>>c
而失去范围。如果没有双字,则必须限制 a
和 b
的输入范围,以免 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>
。你会将你的结果定义为什么?如果您尝试这样做,模板会给您一个编译时错误。
我正在使用 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) 修复,然后其余操作在小数部分完成。
简答:左移。
长答案:
定点数存储为整数,通常是
int
,这是特定平台最快的整数类型。没有小数位的普通整数通常称为
Q0
、Q.0
或QX.0
,其中X是底层存储类型的总位数(通常是int
).要在不同的
Q.X
格式之间转换,左移或右移。例如,要将Q0
中的5转换为Q4中的5,将其左移4位,或乘以16。通常查找或编写一个小型定点库来执行基本计算很有用,例如
a*b>>q
和(a<<q)/b
。因为你会做很多Q.X=Q.Y*Q.Z
和Q.X=Q.Y/Q.Z
,在做计算的时候需要转换格式。正如您可能已经观察到的,使用普通的*
运算符将得到Q.(X+Y)=Q.X*Q.Y
,因此为了使结果适合Q.Z
格式,您需要将结果右移(X+Y-Z)
] 位。- 除法类似,您从标准
/
运算符中得到Q.(X-Y)=Q.X*Q.Y
,要获得Q.Z
格式的结果,您需要在除法之前移动被除数。不同的是,除法是一个昂贵的操作,从头开始写一个快速的操作并不简单。 - 注意您平台的双字支持,这会让您的生活更轻松。使用双字运算,
a*b
的结果可以是a
或b
大小的两倍,这样您就不会因执行a*b>>c
而失去范围。如果没有双字,则必须限制a
和b
的输入范围,以免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>
。你会将你的结果定义为什么?如果您尝试这样做,模板会给您一个编译时错误。