计算没有浮点算术或日志的对数表达式

时间:2015-08-22 18:14:39

标签: c math embedded logarithm lookup-tables

我需要计算嵌入式处理器上<{1}}和floor(ln(u)/ln(1-p))以及 C 的数学表达式0 < u < 1 no floating point arithmetics 且没有0 < p < 1函数。结果是正整数。我知道极限情况(p = 0),我稍后会处理它们......

我认为解决方案涉及lnu范围超过p,并且要求查找表中的对数,但我无法弄清楚究竟是什么:查找表映射到?

结果不一定是100%准确,近似值可以。

谢谢!

1 个答案:

答案 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) < 10240 < 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)