【问题标题】:Fixed point power function定点幂函数
【发布时间】:2019-10-15 07:22:19
【问题描述】:

我对如何处理一些定点计算有疑问。我不知道如何解决它。我知道浮点数很容易,但我想弄清楚如何在定点数中做到这一点。

我有一个定点系统,我在其中对信号 (vSignal) 执行以下方程:

Signal_amplified = vSignal * 10^Exp

vSignal 的最大振幅约为 4e+05,

系统允许表示 2.1475e+09(32 位)信号。所以 Signal_amplified 有一些空间。

为了简单起见,不要假设 Exp 可以从 0 到 10。

假设第一个值为 2.8928。该值在浮点计算时效果很好,因为表达式 10^2.8928 结果为 781。当使用舍入浮点值 781 时,我得到的信号幅度为 3.0085e+08,完全在信号范围内。

如果我尝试用 Q 格式表示值 2.8928,可以说 Q12。该值更改为 11849。现在 10^11849 导致溢出。

应该如何处理这些大数字?我可以使用像 Q4 这样的另一种格式,但即便如此,数字也会变得非常大,而且我变得很差。我非常希望能够以 .001 的精度进行计算,但我只能看到应该如何完成。

最小的工作示例:

int vSignal = 400000

// Floatingpoint -> Goes well
double dExp = 2.89285
double dSignal_amplified = vSignal * std::pow(10,dExp)

// Fixedpoint -> Overflow
int iExp = 11848 // Q12 format
int iSignal_amplified = vSignal * std::pow(10,iExp)
iSignal_amplified =  iSignal_amplified>>12

有什么想法吗?

【问题讨论】:

  • 我对您使用的语言感到困惑。您已经标记了 both C 和 C++,然后在 Python 中提供了一个示例。
  • 是的,很抱歉。我用 Python 模拟,但我用 C/C++ 实现。但同样的问题在两种语言中都存在。这只是提供一个例子。
  • 10^Exp 是通过什么方法定点计算的?这个计算不应该考虑定点单位吗?它不像 10^(2^(-k)) 有任何好的表示可以让你直接将二进制位置从输入转移到输出(你打算之后除以10^(2(-k)) 吗?),那么这一切怎么办?首先工作?
  • 即使没有溢出,您的定点示例代码也是错误的(我猜这回答了我的上述问题)。 10^(x/y)(10^x) / y 不同(在这种情况下为 y = 2^k)。 [注意:这里使用^求幂,而不是xor。]
  • “数值变为 11849”。不,它没有。表示更改为0x2e49。该值更改为 2.892822265625。您混淆了定点数及其二进制表示。

标签: c++ c signal-processing fixed-point


【解决方案1】:

“如果我尝试用 Q 格式表示值 2.8928,比如说 Q12。值更改为 11849。现在 10^11849 会导致溢出。”。

混合类型的数学很难,看起来你应该避免它。你想要的是pow(Q12(10.0), Q12(2.8928)) 或者可能是优化的pow10(Q12(2.8928))。第一个,请参阅my previous answer。后者可以通过硬编码的幂表进行优化。 pow10(2.8928) 当然是 pow10(2) * pow10(.5) * pow10(.25) * pow10(.125) * ... - 2.8928 的二进制表示中的每个 1 对应于单个表条目。您可能希望在 Q19.44 中计算中间结果,并在返回时删除最低 32 位..

编辑:精度

pow10(2^-n)的所有值存储到n=12会有一个小问题,即结果接近1,即1.000562312。如果您将其存储为 Q12,则会失去舍入精度。相反,将pow10(2^-12) 的值存储为Q24,将pow10(2^-121) 的值存储为Q23 等可能是明智的。现在从exp 的LSB 开始评估Q12 pow10(Q12 exp),而不是MSB。当您向上移动到 pow10(0.5) 时,您需要反复移动中间结果,但有一半的时间您可以将其与 Q12 乘法所固有的 >>12 合并。

【讨论】:

  • 感谢您的详细说明。我知道应该避免混合类型的数学,但有时当系统只接受一种类型并且使用另一种类型定义计算时这是必要的。我需要专注于速度,所以我将使用硬编码表的后一种选项。谢谢,再次。
【解决方案2】:

这是一个建议。这只是一个粗略的想法,需要调整和完善。

假设您需要0.01 的精度(您当然可以选择您需要的精度)您可以将指数表示为:Exp = N + M*10^-1 + P*10^-2其中 N、M 和 P 是整数,M 和 P 介于 0 和 9 之间.

然后,您预先计算并舍入 10^(M*10^-1) * 10010^(P*10^-2) * 100 的所有值。它们都在 1 到 1000 之间。将它们存储在查找表中以避免在运行时计算浮点运算。我们将这些查找表称为 A[M] 和 B[P]。

然后你可以计算10^Exp =( 10^N * A[M] * B[P] ) / 10000

根据你说的,A[M] * B[P] 介于 1 和 1,000,000 之间,并且 A 小于 10,因此乘法不应溢出。

我用几个值做了一个快速测试,它似乎给出了可以接受的精度。

【讨论】:

  • 预计算值的四舍五入听起来很吓人。如果您碰巧选择了Exp,例如所有这些都被四舍五入了你可能会在结果中得到一个相当高的错误?我也不确定这如何扩展到更多数字 - 当你添加更多数字时,你很快就会再次溢出。我认为将问题减少到二进制求幂(然后更容易计算出结果小数)并尝试控制ln(10)/ln(2) 指数因子中的错误会更有希望。
  • 四舍五入问题的示例:对于 12 个固定数字,每个表条目中的最大误差为 0.5 * 10^-12,可以聚合到大约 12 x 0.5 * 10^-12 = 6 * 10^-12 相对误差(即结果的最后一位可能会完全丢失此误差)。或者一般来说,如果您有k 数字,那么使用此方案您将有大约k ULP 的错误。可以通过更高的中间分辨率来缓解,但表条目的乘法会更快溢出。
  • 好的 cmets @MaxLanghof。关于精度,很难说是否可以接受。但我的建议的主要问题是,如果你增加位数,它可能会很快溢出。我认为如果从大局来看最好的解决方案:首先,为什么 OP 即使在软件中也不能使用浮点?真的有性能问题吗。如果有,这个放大的信号如何在软件中进一步使用,等等......
  • base-10 很奇怪。计算机不是十进制的。相反,您使用二进制,并且超过 2 位/位。这可能看起来有点贵,但是您现在每个位只有一个值,而不是两个表 A[10]B[10]。因此,对于相同数量的预计算值,您现在得到 20 位精度 = 6 位,而不是 2。
  • 正如我所说,这是一个粗略的想法,需要改进。切换到 base 2 更好,你是对的。
猜你喜欢
  • 1970-01-01
  • 2018-11-30
  • 2018-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
  • 2013-04-22
  • 1970-01-01
相关资源
最近更新 更多