问题是如何在没有浮点运算或长整数计算的情况下计算floor的整数值(log2(5 ^ x))?我正在寻找一种简单,高效和数学上优雅的方式。
观察: 公式只是5 ** x(加1)
中的位数尝试: 我试图将其简化为: 地板(X *的log 2(5))
在我的用例中,x不是非常大,可能只有1-100。虽然适用于小值的优雅公式就足够了,但我会对适用于任何x值的公式/算法感兴趣
我正在制作通用数字的参考软件实现(类型III)。我想通过纯粹使用按位和基本操作使一切都可以轻松转换为微码。这是我需要简化的公式之一。
答案 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;