@Haolong: Java ist eine statisch typisierte Programmiersprache deren Standard-VM aus dem Bytecode vor der Ausführung Maschinencode erzeugen kann. Das heisst wenn da eine Addition steht, dann weis Java was für Typen die Argumente haben und kann bei `int` oder `double` Maschinencode erzeugen der zwei Zahlen addiert.
Python ist eine dynamisch typisierte Programmiersprache deren Standard-VM den vom Compiler erzeugten Bytecode interpretiert. Das heisst wenn da eine Addition steht, dann muss Python erst einmal heraus finden welchen Typ die Argumente haben, beziehungsweise dynamisch den ersten Typ ”bitten” die Addition von den beiden Werten durchzuführen. Und zwar jedes mal aufs Neue wenn der Code an dieser Addition vorbei kommt. So etwas kostet natürlich Zeit. Ausserdem ist Python's `int`-Datentyp nicht auf die Grösse eines Prozessorregisters beschränkt, was dazu führen kann, dass selbst wenn die Typen statisch bekannt wären, es passieren kann, dass eine simpler Maschinencode der zwei ganze Zahlen mit fester Bitgrösse addiert, die in Prozessorregister passen müssen, gar nicht möglich ist.
Bei CPython 2.x kann man den JIT-Compiler Psyco als Modul installieren/importieren um zur Laufzeit zu versuchen Maschinencode erzeugen zu lassen, oder die PyPy-Python-Implementierung. Beide versuchen Typen dynamisch zur Laufzeit zu ermitteln und Maschinencode zu erzeugen der schneller ist als das Interpretieren des Bytecodes. Psyco wird nicht mehr weiterentwickelt (der Entwickler ist bei PyPy aktiv) und nur für 32-Bit-Code verfügbar.
Grundsätzlich habt ihr beide einen nicht gut passenden Algorithmus gewählt, und bei dem dann auch noch einen Fehler gemacht der ihn sehr ineffizient werden lässt. Unpassend deswegen weil ein Sieb schneller ist, während Euer Algorithmus sich eher für Fälle eignet wo man die Obergrenze nicht kennt, also nicht wüsste wie man das Siebt dimensioniert um das Ergebnis sicher darin zu haben. Der Fehler ist die Schleife welche den aktuellen Kandidaten gegen die bereits bekannten Primzahlen testet: die läuft immer komplett durch! Die kann und sollte man abbrechen sobald bekannt ist, dass ein Kandidat keine Primzahl sein kann!
Zu den Quelltexten: Der Java-Quelltext ist lausig/falsch eingerückt. Welche IDE lässt einen das denn *so* eingeben? Man muss sich um Einrückung doch eigentlich gar nicht selber kümmern, im Gegenteil, erfordert es Aufwand Quelltext zu schlecht zu formatieren.
Die Namen sind schlecht gewählt. `eineListe` sagt dem Leser nicht wirklich was für eine Bedeutung dieses Objekt im Programm hat. Zumal in einer statisch typsierten Programmiersprache der Typ ganz sicher nichts im Namen zu suchen hat, denn den kann der Compiler (und die IDE) sicher zu zuverlässig ermitteln und auf Wunsch anzeigen. Oft beispielsweise als Tooltip wenn man mit der Maus über dem Namen im Quelltext verharrt. Es handelt sich hier um die gefundenen Primzahlen und genau das sollte der Name auch vermitteln, denn *das* kann der Rechner nicht herausfinden und anzeigen.
Wenn man Kommentare braucht die einbuchstabige Namen erklären in dem sie durch ein Gleicheitszeichen getrennt ein einzelnes beschreibendes Wort enthalten, dann sollte vielleicht die Variable mit diesem Wort benannt sein!
Aus OOP-Sicht ist das grosser Murks. Weder `zahl`, noch `value` oder `eineListe` machen den Zustand eines Objektes aus. Das sind alles lokale Variablen einer Funktion, also statischer Methode in Java.
`zahl` ist ein schlechter Methodenname. Methodennamen beschreiben die Tätigkeit die von der Methode verrichtet wird.
`value` sollte eigentlich `result` oder `sum` oder so heissen.
`check` könnte auch einen besseren Namen vertragen aber vor allem auch einen passenderen Datentyp: Das ist ein Wahrheitswert.
Der Test mit Modulo ist deutlich einfacher und auch effizienter.
Die Schleife über die bereits bekannten Primzahlen würde man schon etwas länger nicht mehr so schreiben, mit einer manuell verwalteten Indexvariable. Java kennt schon seit vielen Jahren Syntax für „foreach“-Schleifen.
Das würde in Java dann also eher so aussehen:
Code: Alles auswählen
import java.util.ArrayList;
public class Test {
public static void main(String args[]) {
int result = 2;
boolean isPrime;
final ArrayList<Integer> primes = new ArrayList<Integer>();
primes.add(2);
for (int candidate = 3; candidate < 2000000; candidate += 2) {
isPrime = true;
for (int prime : primes) {
if (candidate % prime == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
System.out.println(candidate);
result += candidate;
primes.add(candidate);
}
}
System.out.println(result);
}
}
Etwas unschön ist hier noch das man daran denken muss `result` mit 2 zu initialisieren, weil die zwei aus der Primzahlliste sonst nicht berücksichtigt wird. Hier wäre es besser das Problem besser aufzuteilen und die Summe erst am Ende aus der Liste zu berechnen.
Bei dem Python-Quelltext gibt's auch einige schlechte Namen. Neben `liste` und `i`, die genau so nichtssagend sind wie beim Java-Quelltext, ist `error` hier komisch, denn es handelt sich ja nicht um einen Fehler (auch hier wäre der Typ `bool` angebracht), sondern um die Eigenschaft der Zahle (prim oder nicht).
Einen besseren Namen für `error` braucht man gar nicht suchen weil sich das in Python mit `all()` und einem Generatorausdruck sowieso viel kompakter schreiben lässt:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
def main():
primes = [2]
for candidate in range(3, 2000000, 2):
if all(candidate % prime != 0 for prime in primes):
print(candidate)
primes.append(candidate)
print('---------')
print(primes)
print(sum(primes))
if __name__ == '__main__':
main()