如何加速计算时间?

我编写了以下代码:

combinationsstring = "List of Combinations"
for a = 0, 65 do
    for b = 0, 52 do
        for c = 0, 40 do
            for d = 0, 28 do
                for e = 0, 19 do
                    for f = 0, 11 do
                        for g = 0, 4 do
                            if (((1.15^a)-1)+((20/3)*((1.15^b)-1))
                               +((100/3)*((1.15^c)-1))+(200*((1.15^d)-1))
                               +((2000/3)*((1.15^e)-1))+((8000/3)*((1.15^f)-1))
                               +((40000/3)*((1.15^g)-1))) < 10000 then
                                combinationsstring = combinationsstring
                                    .."\n"..a..", "..b..", "..c..", "..d
                                    ..", "..e..", "..f..", "..g
                            end
                        end
                    end
                end
            end
        end
    end
end

local file = io.open("listOfCombinations.txt", "w")
file:write(combinationsstring)
file:close()

我需要找到所有符合以下等式的数据集

(((1.15 ^ a)-1) + ((20 / 3) * ((1.15 ^ b) -1)) +
((100 / 3) * ((1.15 ^ c) -1)) + (200 * ((1.15 ^ d) -1)) +
((2000 / 3) * ((1.15 ^ e) -1)) + ((8000 / 3) * ((1.15 ^ f) -1)) +
((40000 / 3) * ((1.15 ^ g) -1))) <10000

每个变量(a-g)都是实整数。所以我计算了7个变量中每个的最大值(每个变量的最大值是当其他所有值都为0时)。这些最大值分别为65、52、40、28、19、11和4(62=a,52=b等等)

所以我创建了7个嵌套的循环(如上所示的代码),在中间的块中,我测试了7个值是否符合标准,如果符合,则将它们添加到字符串中。在代码的最后,程序会覆盖一个文件并将最终字符串放在其中,它包含了所有可能的组合。

程序工作得很好,但在这个模拟过程中有31亿次计算,经过一些测试,我发现我的计算机平均每秒进行3000次计算。这意味着总模拟时间约为12天5小时。我根本没有这么多时间,因此我花了整个上午简化了要测试的方程,删除了不必要的代码,这是我的最终结果。

在这里使用嵌套的for循环的方法是否最优?如果是,还有其他方法可以加速这个过程吗?如果不是,请告诉我另一种方法吧。

顺便说一句,我使用Lua,因为这是我最熟悉的语言,但如果你有其他的建议/示例,请使用你的语言并尝试针对这个程序进行优化。

点赞
用户1834147
用户1834147

我不会用 lua,但是我有几个建议:

  • 在开始循环 b 之前,计算并存储 1.15^a-1,可以称之为 fooa
  • 同样,在开始循环 c 之前,计算 fooa+(20/3)*(1.15^b-1),可以称之为 foob
  • 在开始每个循环之前都要做类似的事情。
  • 如果例如 foob 至少为 10000,就退出循环;循环内的内容只会让结果变大。
  • 这可能在 lua 中是无用的或者更糟糕的,但是你真的需要在字符串中累计结果吗?我不知道 lua 如何表示字符串和做连接操作,但是连接操作可能会极大地影响性能。尝试使用列表或数组数据结构。

我还想补充的是,嵌套循环是一个完全合理的解决方案,并且在进行了以上的修改后,这就是我会做的方法。

2013-09-23 03:08:09
用户340947
用户340947

我建议使用静态语言进行这种类型的暴力破解。我曾遇到一个问题(这个),使用 Python 无法解决,但是使用 C++ 的暴力破解方法可以在 30 秒内计算出解决方案。

2013-09-23 03:50:15
用户2633423
用户2633423

既然你也要求使用不同的编程语言来解决问题,那么这里是一个快速而不太完美的 C++ 程序,还引入了 @tmyklebu 的建议。

#include <iostream>
#include <fstream>
#include <cmath>

int main()
{
    std::ofstream os( "listOfCombinations.txt" );
    using std::pow;
    for( double a = 0; a <= 65; ++a ) {
        double aa = (pow(1.15, a) - 1);
        if ( aa > 10000 ) break;
        for( double b = 0; b <= 52; ++b ) {
            double bb = aa + (20/3) * (pow(1.15, b) - 1);
            if ( bb > 10000 ) break;
            for( double c = 0; c <= 40; ++c ) {
                double cc = bb + (100/3) * (pow(1.15, c) - 1);
                if ( cc > 10000 ) break;
                // 以下这行代码为用户提供当前 a、b 和 c 值的可视化反馈
                std::cout << a << "   " << b << "   " << c << std::endl;
                for( double d = 0; d <= 28; ++d ) {
                    double dd = cc + 200 * ( pow(1.15, d) - 1);
                    if ( dd > 10000 ) break;
                    for( double e = 0; e <= 19; ++e ) {
                        double ee = dd + (2000/3) * (pow(1.15, e) - 1);
                        if ( ee > 10000 ) break;
                        for( double f = 0; f <= 11; ++f ) {
                            double ff = ee + (8000/3) * (pow(1.15, f) - 1);
                            if ( ff > 10000 ) break;
                            for( double g = 0; g <= 4; ++g ) {
                                double gg = ff + (40000/3) * (pow(1.15, g) - 1);
                                if ( gg >= 10000 ) break;
                                os << a << ", " << b << ", "
                                    << c << ", " << d << ", "
                                    << e << ", " << f << ", "
                                    << g << "\n";
                            }
                        }
                    }
                }
            }
        }
    }

    return 0;
}
2013-09-24 09:58:22
用户847349
用户847349
local res={}
combinationsstring = "List of Combinations"
--for a = 0, 65 do
        a=0
    for b = 0, 52 do
        for c = 0, 40 do
            for d = 0, 28 do
                for e = 0, 19 do
                    for f = 0, 11 do
                        for g = 0, 4 do
                            if (((1.15^a)-1)+((20/3)*((1.15^b)-1))
                               +((100/3)*((1.15^c)-1))+(200*((1.15^d)-1))
                               +((2000/3)*((1.15^e)-1))+((8000/3)*((1.15^f)-1))
                               +((40000/3)*((1.15^g)-1))) < 10000 then
                                        res[#res+1]={a,b,c,d,e,f,g}
                            end
                        end
                    end
                end
            end
        end
    end
--end

在我的机器上运行需要30秒并占用大约1GB的内存。在32位的Lua VM中无法运行66次,即使使用64位的LuaVM,表的数组部分仍然只能使用32位的整数键。

我已经注释了最外层循环,因此你需要大约30s*66=33分钟。我可能会将其写入66个不同的文件。结果首先存储在一个表中,然后可以连接起来。请查看以下代码:

local res={
    {1,2,3,4,5,6,7},
    {8,9,10,11,12,13,14}
}

for k,v in ipairs(res) do
    -- either concatenate each line and produce a huge string
    res[k]=table.concat(v,", ")
  -- or write each line to a file in this loop
end

local text=table.concat(res,"\n")
print(text)

打印:

1, 2, 3, 4, 5, 6, 7
8, 9, 10, 11, 12, 13, 14
2013-09-25 14:30:25