将整数计算为尽可能接近正方形的值

时间:2016-08-31 11:20:43

标签: python algorithm cython factoring

我有一个逐字节读取文件并将其转换为浮点数组的函数。它还返回所述数组中的元素数。 现在我想将数组重新整形为2D数组,其形状尽可能接近正方形。

作为一个例子,让我们看看数字800:

sqrt(800) = 28.427...

现在我可以通过反复试验弄清楚25*32将是我正在寻找的解决方案。 如果将整数相乘的结果为高,则递减sqrt(舍入为最接近的整数),或者如果结果过低则递增它们。

我知道为质数做这个的算法,但这不是我的要求。我的问题是,即使我实施的暴力方法有时会卡住而且永远不会完成(这是我任意限制迭代的原因):

import math

def factor_int(n):
    nsqrt = math.ceil(math.sqrt(n))

    factors = [nsqrt, nsqrt]
    cd = 0
    result = factors[0] * factors[1]
    ii = 0
    while (result != n or ii > 10000):
        if(result > n):
            factors[cd] -= 1
        else:
            factors[cd] += 1
        result = factors[0] * factors[1]
        print factors, result
        cd = 1 - cd
        ii += 1

    return "resulting factors: {0}".format(factors)

input = 80000
factors = factor_int(input)

使用上面的脚本输出将陷入循环打印

[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0

但我想知道是否有更有效的解决方案呢?当然,我不能成为第一个想做这样的事情的人。

5 个答案:

答案 0 :(得分:2)

def factor_int(n):
    nsqrt = math.ceil(math.sqrt(n))
    solution = False
    val = nsqrt
    while not solution:
        val2 = int(n/val)
        if val2 * val == float(n):
            solution = True
        else:
            val-=1
    return val, val2, n

尝试:

for x in xrange(10, 20):
      print factor_int(x)

答案 1 :(得分:1)

有趣的问题,这是解决问题的可能方法:

import math


def min_dist(a, b):
    dist = []
    for Pa in a:
        for Pb in b:
            d = math.sqrt(
                math.pow(Pa[0] - Pb[0], 2) + math.pow(Pa[1] - Pb[1], 2))
            dist.append([d, Pa])

    return sorted(dist, key=lambda x: x[0])


def get_factors(N):
    if N < 1:
        return N

    N2 = N / 2
    NN = math.sqrt(N)

    result = []
    for a in range(1, N2 + 1):
        for b in range(1, N2 + 1):
            if N == (a * b):
                result.append([a, b])

    result = min_dist(result, [[NN, NN]])
    if result:
        return result[0][1]
    else:
        return [N, 1]


for i in range(801):
    print i, get_factors(i)

此方法的关键是找到[math.sqrt(N),math.sqrt(N)]的笛卡尔点的最小距离,该距离满足要求N = a * b,a&amp; b整数。

答案 2 :(得分:1)

我认为模数运算符非常适合这个问题:

- app1/
- db.sqlite3
- myproject/
- myprojectenv/
- manage.py
- static/

答案 3 :(得分:0)

这是一种直接方法,可找到最小,最接近的整数ab,例如a * b >= na <= b,其中n是任意数字:

def factor_int(n):
    a = math.floor(math.sqrt(n))
    b = math.ceil(n/float(a))
    return a, b

尝试:

for x in xrange(10, 20):
    print factor_int(x)

答案 4 :(得分:0)

根据当前接受的答案,这是一个较短的代码,该代码更短,并且运行时间比其代码少25%-75%(根据基本的时间测试):

from math import sqrt, ceil
def factor_int_2(n):
    val = ceil(sqrt(n))
    while True:
        if not n%val:
            val2 = n//val
            break
        val -= 1
return val, val2

这是我做的一个小而混乱的测试,用于测试该方法的效率:

print("Method 2 is shorter and about {}% quicker".format(100*(1 - timeit(lambda: factor_int_2(12345))/timeit(lambda: factor_int(12345)))))
#returns 'Method 2 is shorter and about 75.03810670186826% quicker'