Ben almış bir problemi # 12 dan Projesi Euler bir programlama egzersiz ve C, Python, Erlang ve Haskell uygulamaları benim (mutlaka değil optimal olan) karşılaştırmak. Daha yüksek yürütme süreleri elde etmek için, orijinal problemde belirtildiği gibi 500 yerine 1000'den fazla bölücü içeren ilk üçgen numarasını ararım.
Sonuç şudur:
C:
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
Python:
lorenzo@enzo:~/erlang$ time ./euler12.py
842161320
real 1m16.632s
user 1m16.370s
sys 0m0.250s
PyPy ile 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
Erlang:
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
Haskell:
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
Özet:
- C:% 100
- Python:% 692 (PyPy ile% 118)
- Erlang:% 436 (RichardC sayesinde% 135)
- Haskell:% 1421
C'nin hesaplamalar için uzun kullandığı ve diğer üçü gibi keyfi uzunluk tamsayıları olmadığı için büyük bir avantajı olduğunu düşünüyorum. Ayrıca önce bir çalışma zamanı yüklemesine gerek yoktur (Diğerleri mi?).
Soru 1:
Erlang, Python ve Haskell, keyfi uzunluk tamsayıları nedeniyle hız kaybediyor MAXINT
mu yoksa değerler daha az olduğu sürece hızını kaybetmiyor mu?
Soru 2: Haskell neden bu kadar yavaş? Frenleri kapatan bir derleyici bayrağı var mı yoksa benim uygulamam mı? (Haskell bana yedi mührü olan bir kitap olduğu için ikincisi oldukça muhtemel.
Soru 3: Faktörleri belirleme şeklimizi değiştirmeden bu uygulamaları nasıl optimize edeceğime dair bazı ipuçları verebilir misiniz? Herhangi bir şekilde optimizasyon: daha güzel, daha hızlı, dile daha "yerli".
DÜZENLE:
Soru 4: İşlevsel uygulamalarım LCO'ya (son çağrı optimizasyonu, kuyruk özyineleme ortadan kaldırılması) izin veriyor ve bu nedenle çağrı yığınına gereksiz kareler eklemekten kaçınıyor mu?
Haskell ve Erlang bilgimin çok sınırlı olduğunu itiraf etmeliyim de, dört dilde mümkün olduğunca aynı algoritmayı uygulamaya çalıştım.
Kullanılan kaynak kodları:
#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]
. yaşasın!