如何加快计算以找到形式为N / 2 ** M的最接近的表示

时间:2017-05-09 16:54:37

标签: python performance minimization

我想在python中找到N / 2 ** M形式的浮点数的最接近表示,其中N和M是整数。我试图使用scipy.optimise中的最小化函数,但它不能局限于N和M是整数的情况。

我最终使用了一个简单的实现,它迭代M和N的值并找到最小值,但这对于许多数组来说计算成本高且耗时,这可能是更好的方法吗?

我的简单实现如下所示:

import numpy as np

def ValueRepresentation(X):
    M, Dp = X
    return M/(2**Dp)

def Diff(X, value):
    return abs(ValueRepresentation(X) - value)

def BestApprox(value):
    mindiff = 1000000000
    for i in np.arange(0, 1000, 1):
        for j in np.arange(0, 60, 1):
            diff = Diff([i, j], value)            
            if diff < mindiff:
                mindiff = diff
                M = i
                Dp = j
    return M, Dp

3 个答案:

答案 0 :(得分:2)

只需使用内置功能:

In [10]: 2.5.as_integer_ratio()  # get representation as fraction
Out[10]: (5, 2)

In [11]: (2).bit_length() - 1    # convert 2**M to M
Out[11]: 1

请注意,所有非无限的非NaN浮点数都是二元有理数,因此我们可以依赖分母为2的精确幂。

答案 1 :(得分:0)

感谢jasonharper,我意识到我的实现效率低得离谱,而且可能更简单。

他的方法的实现如下所示:

def BestApprox_fast(value):
    mindiff = 1000000000
    for Dp in np.arange(0, 32, 1):
        M = round(value*2**Dp)
        if abs(M) < 1000:
            diff = Diff([M, Dp], value)
            if diff < mindiff:
                mindiff = diff
                M_best = M
                Dp_best = Dp
    return M_best, Dp_best

大约快200倍。

答案 2 :(得分:0)

对M和N给出限制,N / 2 ** M的范围是一个明确定义的离散数字刻度:

[0-1000 / 2 ^ 26,501-1000 / 2 ^ 25,501-1000 / 2 ^ 24,... 501-1000 / 2 ^ 1,501-1000 / 2 ^ 0]。

在这个给定的离散集中,不同的子集具有不同的准确度/分辨率。第一个子集[0-1000 / 2 ^ 26]具有2 ^ -26或26个二进制位分辨率的精度。因此,只要给定的数字落在相应的连续域[0,1000 / 2 ^ 26]中,可实现的最佳精度为2 ^ -26。接着,当给定数量超出第一个域但落入域[500/2 ^ 25,1000 / 2 ^ 25]时,最佳准确度为2 ^ 25,这对应于第二个子集[501-1000 / 2 ^ 25] ]。 (注意离散集和连续域之间的区别。)

根据上述逻辑,我们知道由M定义的最佳准确度取决于给定数字在比例上的位置。因此我们可以按照以下python代码实现它:

import numpy as np

limits = 1000.0/2**np.arange(0,61)

a = 103.23    # test value
for i in range(60,-1,-1):
    if a <= limits[i]:
        N = i
        M = round(a * 2**N)
        r = [M, N]
        break

if a > 1000:
    r = [round(a), 0]

此解决方案具有O(c)执行时间,因此非常适合多次调用。