Haftungsausschluss
Ich weiß, dass künstliche Benchmarks böse sind. Sie können Ergebnisse nur für eine ganz bestimmte enge Situation anzeigen. Ich gehe nicht davon aus, dass eine Sprache wegen der dummen Bank besser ist als die andere. Ich frage mich jedoch, warum die Ergebnisse so unterschiedlich sind. Bitte sehen Sie meine Fragen unten.
Beschreibung des mathematischen Benchmarks
Benchmark ist eine einfache mathematische Berechnung, um Paare von Primzahlen zu finden, die sich um 6 unterscheiden (sogenannte sexy Primzahlen ). ZB wären sexy Primzahlen unter 100:(5 11) (7 13) (11 17) (13 19) (17 23) (23 29) (31 37) (37 43) (41 47) (47 53) (53 59) (61 67) (67 73) (73 79) (83 89) (97 103)
Ergebnistabelle
In Tabelle: Berechnungszeit in Sekunden Ausführen: Alle außer Factor wurden in VirtualBox ausgeführt (Debian instabiler amd64-Gast, Windows 7 x64-Host). CPU: AMD A4-3305M
Sexy primes up to: 10k 20k 30k 100k
Bash 58.00 200.00 [*1] [*1]
C 0.20 0.65 1.42 15.00
Clojure1.4 4.12 8.32 16.00 137.93
Clojure1.4 (optimized) 0.95 1.82 2.30 16.00
Factor n/a n/a 15.00 180.00
Python2.7 1.49 5.20 11.00 119
Ruby1.8 5.10 18.32 40.48 377.00
Ruby1.9.3 1.36 5.73 10.48 106.00
Scala2.9.2 0.93 1.41 2.73 20.84
Scala2.9.2 (optimized) 0.32 0.79 1.46 12.01
[* 1] - Ich habe Angst, mir vorzustellen, wie viel Zeit es dauern wird
Codeauflistungen
C:
int isprime(int x) {
int i;
for (i = 2; i < x; ++i)
if (x%i == 0) return 0;
return 1;
}
void findprimes(int m) {
int i;
for ( i = 11; i < m; ++i)
if (isprime(i) && isprime(i-6))
printf("%d %d\n", i-6, i);
}
main() {
findprimes(10*1000);
}
Rubin:
def is_prime?(n)
(2...n).all?{|m| n%m != 0 }
end
def sexy_primes(x)
(9..x).map do |i|
[i-6, i]
end.select do |j|
j.all?{|j| is_prime? j}
end
end
a = Time.now
p sexy_primes(10*1000)
b = Time.now
puts "#{(b-a)*1000} mils"
Scala:
def isPrime(n: Int) =
(2 until n) forall { n % _ != 0 }
def sexyPrimes(n: Int) =
(11 to n) map { i => List(i-6, i) } filter { _ forall(isPrime(_)) }
val a = System.currentTimeMillis()
println(sexyPrimes(100*1000))
val b = System.currentTimeMillis()
println((b-a).toString + " mils")
Scala opimiert isPrime
(die gleiche Idee wie bei der Clojure-Optimierung):
import scala.annotation.tailrec
@tailrec // Not required, but will warn if optimization doesn't work
def isPrime(n: Int, i: Int = 2): Boolean =
if (i == n) true
else if (n % i != 0) isPrime(n, i + 1)
else false
Clojure:
(defn is-prime? [n]
(every? #(> (mod n %) 0)
(range 2 n)))
(defn sexy-primes [m]
(for [x (range 11 (inc m))
:let [z (list (- x 6) x)]
:when (every? #(is-prime? %) z)]
z))
(let [a (System/currentTimeMillis)]
(println (sexy-primes (* 10 1000)))
(let [b (System/currentTimeMillis)]
(println (- b a) "mils")))
Clojure optimiert is-prime?
:
(defn ^:static is-prime? [^long n]
(loop [i (long 2)]
(if (= (rem n i) 0)
false
(if (>= (inc i) n) true (recur (inc i))))))
Python
import time as time_
def is_prime(n):
return all((n%j > 0) for j in xrange(2, n))
def primes_below(x):
return [[j-6, j] for j in xrange(9, x+1) if is_prime(j) and is_prime(j-6)]
a = int(round(time_.time() * 1000))
print(primes_below(10*1000))
b = int(round(time_.time() * 1000))
print(str((b-a)) + " mils")
Faktor
MEMO:: prime? ( n -- ? )
n 1 - 2 [a,b] [ n swap mod 0 > ] all? ;
MEMO: sexyprimes ( n n -- r r )
[a,b] [ prime? ] filter [ 6 + ] map [ prime? ] filter dup [ 6 - ] map ;
5 10 1000 * sexyprimes . .
Bash (zsh):
#!/usr/bin/zsh
function prime {
for (( i = 2; i < $1; i++ )); do
if [[ $[$1%i] == 0 ]]; then
echo 1
exit
fi
done
echo 0
}
function sexy-primes {
for (( i = 9; i <= $1; i++ )); do
j=$[i-6]
if [[ $(prime $i) == 0 && $(prime $j) == 0 ]]; then
echo $j $i
fi
done
}
sexy-primes 10000
Fragen
- Warum ist Scala so schnell? Liegt es an der statischen Eingabe ? Oder nutzt es JVM nur sehr effizient?
Warum so ein großer Unterschied zwischen Ruby und Python? Ich dachte, diese beiden sind nicht ganz anders. Vielleicht ist mein Code falsch. Bitte erleuchte mich! Vielen Dank.UPD Ja, das war ein Fehler in meinem Code. Python und Ruby 1.9 sind ziemlich gleich.- Wirklich beeindruckender Produktivitätssprung zwischen Ruby-Versionen.
- Kann ich Clojure-Code durch Hinzufügen von Typdeklarationen optimieren? Wird es helfen?
C: 2.723s
Go: 2.743s
.
sqrt
für diese Prüfung nicht berechnen . Sie können das Quadrat von i
wie infor (i = 2; i * i <= x; ++i) ...
isPrime
mit @tailrec
, um sicherzustellen, dass Sie die Schwanzrekursion verwenden. Es ist leicht, versehentlich etwas zu tun, das eine Schwanzrekursion verhindert, und diese Anmerkung sollte Sie warnen, wenn dies passiert.
sqrt(n)
aber das kann einige Zeit dauern, um zu berechnen. Außerdem druckt Ihr C-Code die Primzahlen so aus, wie sie gefunden werden, während Ihre anderen Sprachen sie in Listen berechnen und dann ausdrucken. Während C nicht überraschend das schnellste ist, können Sie es möglicherweise schneller bekommen.