【问题标题】:How to compute floor(log2(5**x)) without floating point arithmetic or long integer computation如何在没有浮点运算或长整数计算的情况下计算 floor(log2(5**x))
【发布时间】:2017-11-10 18:56:48
【问题描述】:

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

观察: 公式就是5**x中的位数(加1)

尝试: 我试图将其简化为: 楼层(x*log2(5))

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

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

【问题讨论】:

  • 5x 中的位数是上限(x*log2(5)),而不是下限。你需要 3 位来存储 51.
  • 我认为是 floor(x*log2(5)) + 1。让我验证一下。编辑:是的,看起来我是对的。 f(2) = f(3) 在我们使用 floor 然后加 1 时有效,但对于 ceil 无效。
  • 我认为你是对的。 4 需要 3 位来存储它。
  • 对于有限大小的情况,您可以使用具有长整数算法的系统来计算表吗?对于 [1,N] 中的每个整数 n,计算 5 的最小整数幂 x,使得 2n 不大于 5x。存储 x 和 n 之间的映射。
  • 是的,x

标签: math floating-point


【解决方案1】:

正如您正确指出的那样,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 将是整数除法,而不是浮点数。

【讨论】:

  • 作为替代方案,您可以只执行output = result intdiv scale,其中intdiv 是带截断的整数除法,因为这也将处理您的floor 要求。
  • 是的,这也是必要的,因为我不能使用浮动操作
【解决方案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,这还不错。

【讨论】:

    【解决方案3】:

    为了一种简单、高效且数学上优雅的方式...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 是“最简单的”并且是“最佳”的候选者。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 2018-03-22
      相关资源
      最近更新 更多