Project Euler의 문제 # 12 를 프로그래밍 연습으로 취하고 C, Python, Erlang 및 Haskell의 ( 실제로는 최적이 아닌) 구현을 비교했습니다. 더 높은 실행 시간을 얻기 위해 원래 문제에서 설명한대로 500 대신 1000이 아닌 제수가있는 첫 번째 삼각형 수를 검색합니다.
결과는 다음과 같습니다.
씨:
lorenzo@enzo:~/erlang$ gcc -lm -o euler12.bin euler12.c
lorenzo@enzo:~/erlang$ time ./euler12.bin
842161320
real 0m11.074s
user 0m11.070s
sys 0m0.000s
파이썬 :
lorenzo@enzo:~/erlang$ time ./euler12.py
842161320
real 1m16.632s
user 1m16.370s
sys 0m0.250s
PyPy가 포함 된 Python :
lorenzo@enzo:~/Downloads/pypy-c-jit-43780-b590cf6de419-linux64/bin$ time ./pypy /home/lorenzo/erlang/euler12.py
842161320
real 0m13.082s
user 0m13.050s
sys 0m0.020s
얼랭 :
lorenzo@enzo:~/erlang$ erlc euler12.erl
lorenzo@enzo:~/erlang$ time erl -s euler12 solve
Erlang R13B03 (erts-5.7.4) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.4 (abort with ^G)
1> 842161320
real 0m48.259s
user 0m48.070s
sys 0m0.020s
하스켈 :
lorenzo@enzo:~/erlang$ ghc euler12.hs -o euler12.hsx
[1 of 1] Compiling Main ( euler12.hs, euler12.o )
Linking euler12.hsx ...
lorenzo@enzo:~/erlang$ time ./euler12.hsx
842161320
real 2m37.326s
user 2m37.240s
sys 0m0.080s
요약:
- C : 100 %
- Python : 692 % (PyPy 사용시 118 %)
- 얼랭 : 436 % (RichardC 덕분에 135 %)
- 하스켈 : 1421 %
C는 계산에 오래 사용하고 다른 세 정수는 임의의 길이 정수가 아니기 때문에 큰 이점이 있다고 가정합니다. 또한 런타임을 먼저로드 할 필요가 없습니다 (다른 작업을 수행합니까?).
질문 1 :
Erlang, Python 및 Haskell은 임의의 길이 정수를 사용하여 속도를 잃 MAXINT
습니까?
질문 2 : Haskell은 왜 그렇게 느립니까? 브레이크를 끄는 컴파일러 플래그가 있습니까, 아니면 내 구현입니까? (후자는 Haskell이 나에게 7 개의 인장이있는 책이므로 가능성이 높다.)
질문 3 : 요소를 결정하는 방식을 변경하지 않고 이러한 구현을 최적화하는 방법에 대한 힌트를 제공 할 수 있습니까? 어떤 방식 으로든 최적화 : 언어에 대해 더 좋고 빠르며 "네이티브"합니다.
편집하다:
질문 4 : 기능 구현에서 LCO (마지막 호출 최적화, 일명 테일 재귀 제거)를 허용하므로 호출 스택에 불필요한 프레임을 추가하지 않습니까?
나는 Haskell과 Erlang 지식이 매우 제한되어 있음을 인정해야하지만 4 가지 언어에서 가능한 한 비슷한 알고리즘을 구현하려고했습니다.
사용 된 소스 코드 :
#include <stdio.h>
#include <math.h>
int factorCount (long n)
{
double square = sqrt (n);
int isquare = (int) square;
int count = isquare == square ? -1 : 0;
long candidate;
for (candidate = 1; candidate <= isquare; candidate ++)
if (0 == n % candidate) count += 2;
return count;
}
int main ()
{
long triangle = 1;
int index = 1;
while (factorCount (triangle) < 1001)
{
index ++;
triangle += index;
}
printf ("%ld\n", triangle);
}
#! /usr/bin/env python3.2
import math
def factorCount (n):
square = math.sqrt (n)
isquare = int (square)
count = -1 if isquare == square else 0
for candidate in range (1, isquare + 1):
if not n % candidate: count += 2
return count
triangle = 1
index = 1
while factorCount (triangle) < 1001:
index += 1
triangle += index
print (triangle)
-module (euler12).
-compile (export_all).
factorCount (Number) -> factorCount (Number, math:sqrt (Number), 1, 0).
factorCount (_, Sqrt, Candidate, Count) when Candidate > Sqrt -> Count;
factorCount (_, Sqrt, Candidate, Count) when Candidate == Sqrt -> Count + 1;
factorCount (Number, Sqrt, Candidate, Count) ->
case Number rem Candidate of
0 -> factorCount (Number, Sqrt, Candidate + 1, Count + 2);
_ -> factorCount (Number, Sqrt, Candidate + 1, Count)
end.
nextTriangle (Index, Triangle) ->
Count = factorCount (Triangle),
if
Count > 1000 -> Triangle;
true -> nextTriangle (Index + 1, Triangle + Index + 1)
end.
solve () ->
io:format ("~p~n", [nextTriangle (1, 1) ] ),
halt (0).
factorCount number = factorCount' number isquare 1 0 - (fromEnum $ square == fromIntegral isquare)
where square = sqrt $ fromIntegral number
isquare = floor square
factorCount' number sqrt candidate count
| fromIntegral candidate > sqrt = count
| number `mod` candidate == 0 = factorCount' number sqrt (candidate + 1) (count + 2)
| otherwise = factorCount' number sqrt (candidate + 1) count
nextTriangle index triangle
| factorCount triangle > 1000 = triangle
| otherwise = nextTriangle (index + 1) (triangle + index + 1)
main = print $ nextTriangle 1 1
Euler12[x_Integer] := Module[{s = 1}, For[i = 2, DivisorSigma[0, s] < x, i++, s += i]; s]
. 만세!