Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Haskell中的递归函数非常慢_Performance_Haskell_Lazy Evaluation - Fatal编程技术网

Performance Haskell中的递归函数非常慢

Performance Haskell中的递归函数非常慢,performance,haskell,lazy-evaluation,Performance,Haskell,Lazy Evaluation,我已经编写了一个简单的Haskell程序来解决一个难题。该算法是正确的,它为n=40生成了正确的结果,即14466。然而,对于n=100程序变得如此缓慢,以至于我甚至没有足够的耐心等待它结束 我不明白为什么它这么慢,因为我希望它能缓存中间函数调用的所有结果,你知道,Haskell是一种懒惰的语言 我的编译器是GHCi 7.6.3 我尝试过分析,但这告诉我99.9%的时间都花在isLoosing函数上 isLoosing :: Int -> Int -> Bool isLoosing

我已经编写了一个简单的Haskell程序来解决一个难题。该算法是正确的,它为
n=40
生成了正确的结果,即14466。然而,对于
n=100
程序变得如此缓慢,以至于我甚至没有足够的耐心等待它结束

我不明白为什么它这么慢,因为我希望它能缓存中间函数调用的所有结果,你知道,Haskell是一种懒惰的语言

我的编译器是GHCi 7.6.3

我尝试过分析,但这告诉我99.9%的时间都花在isLoosing函数上

isLoosing :: Int -> Int -> Bool
isLoosing x y
    | y < x             = isLoosing y x
    | x == 0            = True
    | x == 1            = False
    | y `mod` x == 0    = False
    | otherwise         = and [ not (isLoosing (y-x*m) x) |
                                m <- [1..(y `div` x)] ]

loosingSum :: Int -> Int
loosingSum n = sum  [ x + y |
                        x <- [1..(n-1)],
                        y <- [(x+1)..n],
                        isLoosing x y == True ]

main = print $ loosingSum 40
isLoosing::Int->Int->Bool
isLoosing x y
|yx我发现需要使用记忆来加快速度。我找到了一个很好的库来为我这样做,如下所示。此代码现在运行速度为0.12s,但不幸的是,这仍然太慢。使用
n=10000
运行它同样需要相当多的内插时间,而使用中的类似算法则需要几秒钟C++,所以我开始想哈斯克尔不是解决问题的办法……
import Data.MemoCombinators (memo2,integral)

bigN :: Int
bigN = 100

isLoosingCached = memo2 integral integral isLoosing

isLoosing :: Int -> Int -> Bool
isLoosing x y
    | y < x             = isLoosingCached y x
    | x == 0            = True
    | x == 1            = False
    | y `mod` x == 0    = False
    | otherwise         = and [ not (isLoosingCached (y-x*m) x) |
                            m <- [1..(y `div` x)] ]

loosingSum :: Int
loosingSum = sum    [ x + y |
                        x <- [1..(n-1)],
                        y <- [(x+1)..n],
                        isLoosingCached x y == True ]
                where n = bigN

main = print $ loosingSum
import Data.memombinators(memo2,integral)
bigN::Int
bigN=100
isLoosingCached=memo2整数isLoosing
isLoosing::Int->Int->Bool
isLoosing x y
|y嗯,好,有趣。有一件事我不明白,为什么编译器不自动地这样做?@ PopoVijsJGC从不记忆,因为如果每个函数调用都保存了,它占用太多内存。显示你的C++解决方案。你可能会把苹果和橘子比较。你可能是对的……我把C++代码添加到我的答案中。“所以我开始认为Haskell并不是解决所有问题的方法”:亵渎者!最大的区别是C代码预先分配了一个数组,但Haskell代码不断地分配新的cons单元格。也就是说,你在比较两种完全不同的算法。
#include <iostream>
#include <stdint.h>
#define N 10000
short STATES[N + 1][N + 1];
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    uint64_t sum = 0;
    for (int y = 0; y <= N; y++)
    {
        STATES[0][y] = 1;
        STATES[1][y] = -1;
    }
    for (int x = 2; x < N; x++)
        for (int y = x; y <= N; y += x)
            STATES[x][y] = -1;
    for (int x = 2; x < N; x++)
    {
        for (int y = x + 1; y <= N; y++)
        {
            if (STATES[x][y] == 0)
            {
                int k;
                for (int y_ = y - x; y_ > 0; y_ -= x)
                {
                    if (y_ > x)
                        k = STATES[x][y_] * -1;
                    else
                        k = STATES[y_][x] * -1;
                    if (k == -1)
                        break;
                }
                STATES[x][y] = k;
            }
            if (STATES[x][y] == 1)
                sum += x + y;
        }
        cout << sum << endl;
        system("pause");
    }
}