我需要计算嵌入式处理器上<{1}}和floor(ln(u)/ln(1-p))
以及 C 的数学表达式0 < u < 1
no floating point arithmetics 且没有0 < p < 1
函数。结果是正整数。我知道极限情况(p = 0),我稍后会处理它们......
我认为解决方案涉及ln
和u
范围超过p
,并且要求查找表中的对数,但我无法弄清楚究竟是什么:查找表映射到?
结果不一定是100%准确,近似值可以。
谢谢!
答案 0 :(得分:3)
此功能的最大值主要取决于精度限制;也就是说,固定点值可以任意接近限制(u -> 0)
或(1 - p -> 1)
。
如果我们假设(k)
小数位,例如,使用限制:u = (2^-k)
和1 - p = 1 - (2^-k)
,
那么最大值是:k / (k - log2(2^k - 1))
(作为自然对数的比率,我们可以自由使用任何基数,例如lb(x)
或log2
)
与njuffa's回答不同,我选择了查找表方法,使用k = 10
小数位来表示0 < frac(u) < 1024
和0 < frac(p) < 1024
。这需要一个带有2^k
条目的日志表。使用32位表值,我们只查看4KiB
表。
除此之外,你正在使用足够的内存,你可以认真考虑使用“软浮动”的相关部分。图书馆。例如,k = 16
会产生256KiB
LUT。
我们正在计算- log2(i / 1024.0)
的值0 < i < 1024
。由于这些值在开放区间(0, k)
中,我们只需要4个二进制数来存储整数部分。因此,我们将预先计算的 LUT存储为32位[4.28]
定点格式:
uint32_t lut[1024]; /* never use lut[0] */
for (uint32_t i = 1; i < 1024; i++)
lut[i] = (uint32_t) (- (log2(i / 1024.0) * (268435456.0));
鉴于:u, p
由[0.10]
中的[1, 1023]
定点值代表:
uint32_t func (uint16_t u, uint16_t p)
{
/* assert: 0 < u, p < 1024 */
return lut[u] / lut[1024 - p];
}
我们可以轻松地针对“天真”的所有有效(u, p)
对进行测试。浮点评估:
floor(log(u / 1024.0) / log(1.0 - p / 1024.0))
只会在以下情况下出现不匹配(+1太高):
u = 193, p = 1 : 1708 vs 1707 (1.7079978488147417e+03)
u = 250, p = 384 : 3 vs 2 (2.9999999999999996e+00)
u = 413, p = 4 : 232 vs 231 (2.3199989016957960e+02)
u = 603, p = 1 : 542 vs 541 (5.4199909906444600e+02)
u = 680, p = 1 : 419 vs 418 (4.1899938077226307e+02)
最后,事实证明,使用[3.29]
定点格式的自然对数可以提供更高的精度,其中:
lut[i] = (uint32_t) (- (log(i / 1024.0) * (536870912.0));
只会产生一个“不匹配”,但'bignum'精度表明它是正确的:
u = 250, p = 384 : 3 vs 2 (2.9999999999999996e+00)