如何计算没有浮点运算或长整数计算的floor(log2(5 ** x))

时间:2017-11-10 18:56:49

标签: math floating-point

问题是如何在没有浮点运算或长整数计算的情况下计算floor的整数值(log2(5 ^ x))?我正在寻找一种简单,高效和数学上优雅的方式。

观察: 公式只是5 ** x(加1)

中的位数

尝试: 我试图将其简化为: 地板(X *的log 2(5))

在我的用例中,x不是非常大,可能只有1-100。虽然适用于小值的优雅公式就足够了,但我会对适用于任何x值的公式/算法感兴趣

我正在制作通用数字的参考软件实现(类型III)。我想通过纯粹使用按位和基本操作使一切都可以轻松转换为微码。这是我需要简化的公式之一。

3 个答案:

答案 0 :(得分:4)

正如您所说,log2(5**x) == x * log2(5)log2(5)是常量,可以近似为2.3219281

但是,每个问题都不允许浮动。不是问题!

log2_5 = 23219281;
scale = 10000000; // note log2_5/scale is the actual value
result = x * log2_5;
output = (result - (result % scale)) / scale;

通过result减少result % scale,将其除以scale将是整数除法,而不是浮点数。

答案 1 :(得分:2)

这是一个非常粗略的近似值,但如果你想在心理上获得它可以提供帮助

5^3 = 125
2^7 = 128

所以提升到n的力量:

5^n ~~ 2^(7n/3)

所以5 ^ 12接近2 ^ 28可能需要最多29位。

有点过高估计,因为2 ^ 7> 5 ^ 3,所以28位就足够了,一个很好的用法就是简单地将分数上半部分。

如果我在Smalltalk评估:

(1 to: 50) reject: [:i | (5 raisedTo: i) highBit = (i*7/3) ceiling].

我明白了:

#(31 34 37 40 43 46 49)

你看到非常简单的配方可以达到5 ^ 30,这并不是那么糟糕。

答案 2 :(得分:1)

  

以简单,高效和数学优雅的方式...... floor(x*log2(5))

由于x的整数值为1到100,因此可以进行各种测试以找到最好的"使用整数乘法和除以power_of_2  f(x) = x*a integer_divide power_of_2

有关 f(x) = floor(x*log2(5)) = floor(x*some_float_c) some_float_c的值受以下100个最小值和最大值限制。

x   f(x)    mn  mx
        f(x)/x  (f(x) + 1)/x
1   2   2.00000 3.00000
2   4   2.00000 2.50000
3   6   2.00000 2.33333
... 
59  136 2.30508 2.32203
... 
87  202 2.32184 2.33333
... 
98  227 2.31633 2.32653
99  229 2.31313 2.32323
100 232 2.32000 2.33000

最大分钟为2.32184,最小分数为2.32203,:

2.32184... <= some_float_c < 2.32203...

由于我们无法使用float,请找到some_integer/some_power_of_2

2.32184... <= some_integer/some_power_of_2 < 2.32203...
ceil(some_power_of_2 * 2.32184...) <= some_integer < floor(some_power_of_2 * 2.32203...)

        min     max
        2.32184 2.32203
2       5       4
4       10      9
8       19      18
...
1024    2378    2377
2048    4756    4755
4096    9511    9511  < first one where min <= max
8192    19021   19022

所以9511/4096是最简单的&#34;并且是最好的&#34;候选者。

f(x) = (x*9511) integer_divide_by_power_of_2 4096

// In C
unsigned y = (x*9511u) >> 12;