Java schneller als C++?!



  • Hallo,

    man könnte ja meinen, dass Java, aufgrund der Virtuellen Maschine, beim Ausführen langsamer ist als C++. Da mich interessiert hat wie viel schneller C++ ist, habe ich eine kleine Konsolenanwendung in beiden Spachen geschrieben, welches die Zahl PI mit Hilfe der "Streifenmethode des Archimedes" berechnet. Vor und nach dem Ausführen des Programmes, habe ich die Zeit gestoppt, die ich am Ende verglichen habe.

    Beide Programme sind also identisch und werden nun von mir auf dem gleichen System nacheinander ausgeführt.

    Verwendete Java Version: "Java SDK 1.5.0"
    Verwendete C++ Version: zuerst "Visual C++ .NET" später "Borland C++ 5.5"

    Das Ergebnis, war erschreckend. Java hat für das berechnen von PI auf die 15te Stelle(wenn man den Viertelkreis in 10000000 Flächenstreifen einteilt) eine gute Sekunde wengier gebraucht als C++. Es war dabei egal, ob ich es nun mit "Visual C++ .NET" oder mit "Borland C++ 5.5" versucht habe.

    Ergebnis Java 1.5.0:
    PI: 3.141592653552359
    Zeit: 2.75s
    
    Ergebnis Visual C++ .NET:
    PI: 3.141592653552359
    Zeit: 4.578s
    
    Ergebnis Borland C++ 5.5:
    PI: 3.141592653552337
    Zeit: 3.844s
    

    Wie ist das möglich?



  • Wo sind die Quelltexte? Wo sind die verwendeten Compiler-Optionen?



  • Sourcecode C++:

    #include <stdio.h>
    #include <conio.h>
    #include <math.h>
    #include <time.h>
    
    double calculatePI(double);
    
    int main()
    {
    	int zeit1 = clock();
    
    	printf("PI: %.15f\n", calculatePI(10000000.0));
    
    	int zeit2 = clock();
    	printf("Zeit: %.3fs", ((zeit2 - zeit1) / 1000.0));
    
    	getch();
    	return 0;
    }
    
    double calculatePI(double n)
    {
    	// Untersumme
    	double untersumme = 0;
    	for(double i = 1; i < n; i++)
    		untersumme += 4.0 * sqrt(1 - pow(i / n, 2.0)) / n;
    
    	// Obersumme
    	double obersumme = 0;
    	for(double i = 0; i < n; i++)
    		obersumme += 4.0 * sqrt(1 - pow(i / n, 2.0)) / n;
    	return (untersumme + obersumme) / 2.0;
    }
    

    Sourcecode Java:

    import java.util.Date;
    
    public class PI
    {
    	Date zeit1;
    	Date zeit2;
    	public PI()
    	{
    		zeit1 = new Date();
    		System.out.println("PI: " + calculatePI(10000000.0));
    		zeit2 = new Date();
    		System.out.println("Zeit: " + (zeit2.getTime() - zeit1.getTime()) / 1000.0 + "s");
    	}
    
    	public double calculatePI(double n)
    	{
    		// Untersumme
    		double untersumme = 0;
    		for(double i = 1; i < n; i++)
    			untersumme += 4.0 * Math.sqrt(1 - Math.pow(i / n, 2.0)) / n;
    
    		// Obersumme
    		double obersumme = 0;
    		for(double i = 0; i < n; i++)
    			obersumme += 4.0 * Math.sqrt(1 - Math.pow(i / n, 2.0)) / n;
    		return (untersumme + obersumme) / 2.0;
    	}
    
    	public static void main(String[] args)
    	{
    		new PI();
    	}
    }
    

    Ich habe keine Compilteroptionen verwendet!

    Bitte gewöhnt euch mal an nicht immer zuerst von der Doofheit des Posters auszugehen. Ist ja schlimm.



  • Ich habe keine Compilteroptionen verwendet!

    Na dann liegt es wohl an deiner Doofheit.



  • Wäre dann nett wenn du mich aufklären würdest. Welche Compiliteroptionen hätte ich denn nutzen müssen?



  • Sollte man wirklich mit der Date Klasse solche Messungen durchführen?



  • Gute Frage. Ich denke die Methode "System.currentTimeMillis()" hätte es auch gebracht. Denke aber, dass sich das ganze nur positiv auf das Programm auswirken würde. Und das würde nur mehr für Java sprechen.



  • Aufgrund eines (auch noch unbrauchbaren) Fallbeispiels kann man nicht folgern, dass Java generell schneller ist als C++. Falls deine Frage allerdings war, ob Java nicht bei bestimmten Dingen schneller sein kann als C++ lautet die Antwort: Ja natürlich, und was ist jetzt daran so toll?



  • Optimizer schrieb:

    ...ob Java nicht bei bestimmten Dingen schneller sein kann als C++ lautet die Antwort: Ja natürlich, und was ist jetzt daran so toll?

    hast du einen beispielcode, bei dem java definitiv schneller ist als c++?



  • Wäre dann nett wenn du mich aufklären würdest. Welche Compiliteroptionen hätte ich denn nutzen müssen?

    Gibt es beim Visual Studio nicht von vorneherein zwei Projekteinstellungen: Debug und Release, wobei Debug vorausgewählt ist? Wählt einfach mal Release. Allein das sollte schon deutlich an geschwindigkeit bringen.

    Wenn du weiter tunen willst solltest du natürlich speziell auf deinen Prozessor optimieren lassen.



  • Optimizer schrieb:

    Aufgrund eines (auch noch unbrauchbaren) Fallbeispiels kann man nicht folgern, dass Java generell schneller ist als C++. Falls deine Frage allerdings war, ob Java nicht bei bestimmten Dingen schneller sein kann als C++ lautet die Antwort: Ja natürlich, und was ist jetzt daran so toll?

    Wieso bist du auf der einen Seite so korrekt und auf der anderen Seite wieder nich? Warum ist es dein unbrauchbares Fallbeispiel?

    Ich habe mich bemüht gleiche Bedingungen zu schaffen.

    - selber Anwender
    - selbes System
    - selbe Problematik
    - selber Zeitaufwand

    Normal hätte man doch vermuten müssen, dass C++ schneller ist, allein schon weil es keine "Virtuelle Maschiene" hat.

    Meine ursprüngliche Frage war, wie es sein kann, dass Java in diesem konkreten Test besser abgeschnitten hat und bisher habe ich noch keine vernümpftig Antwort erhalten :(.



  • Gibt es beim Visual Studio nicht von vorneherein zwei Projekteinstellungen: Debug und Release, wobei Debug vorausgewählt ist? Wählt einfach mal Release. Allein das sollte schon deutlich an geschwindigkeit bringen.

    Wenn du weiter tunen willst solltest du natürlich speziell auf deinen Prozessor optimieren lassen.

    Das ist doch mal ein Beitrag der konstruktiv ist :).

    Leider ist das Programm in C++ auf "Release" immernoch langsamer als Java. Und immer speziell auf die CPU zu optimieren, wäre ja auch nicht gerade das Wahre.



  • net schrieb:

    Optimizer schrieb:

    ...ob Java nicht bei bestimmten Dingen schneller sein kann als C++ lautet die Antwort: Ja natürlich, und was ist jetzt daran so toll?

    hast du einen beispielcode, bei dem java definitiv schneller ist als c++?

    Codebeispiele sind sinnlos, weil es immer ein Zusammenspiel von Compiler, plattformspezifischer Optimierung, Programmarchitektur und hunderten weiteren Sachen ist.

    In Java kann ich nen String 20mal rumreichen und an hunderte Objekte als Datenelement zuweisen und es kostet praktisch nichts. In C++ geht das natürlich auch. std::string ist aber meistens nicht als shared buffer implementiert und du musst z.B. mit C-Strings arbeiten oder ne andere Klasse nutzen. Dann hast du beim sharen aber wieder das Speicherverwaltungsproblem, außer du nimmst den Overhead von refcounting in Kauf.
    Mit genügend großem Aufwand wirst du schon auf eine Lösung kommen, mit der C++ ohne Probleme dann mithalten kann, du kannst aber nicht immer genügend großen Aufwand betreiben.

    Wenn du dynamisch sehr viele kurzlebige Objekte allokierst, kann der GC sehr rocken, wenn du für C++ nen eigenen Allokator speziell für diesen Zweck schreibst, hast du wieder geilen Aufwand (frag volkard, ob er dir seinen gibt. ach ne, den hat er gekickt, weil er doch nicht zufrieden war) und kannst dann wieder mithalten. Für realistische Fälle = realistische Entwicklungszeit/Kosten gibt es immer wieder Fälle, wo du mit Java schneller bist. Und natürlich auch, wo du langsamer bist.
    Der eigentliche Witz ist aber, dass man in C++ dann nicht die selbe Architektur wählt, die man für Java wählt. Deshalb ist es nie wirklich vergleichbar.

    Keine Ahnung, warum das so unvorstellbar ist. Wenn ne Firma mehrere Mannjahre inverstiert, um irgendwas zu optimieren, kann es doch durchaus sein, dass du mit weniger Mannjahren auf eine weniger optimale Lösung kommst.

    Ich stoße immer wieder auf Sachen, wenn ich überhaupt mir die Mühe mach, das zu messen. Du denkst, ich will mich jetzt herausreden, aber ich tu mir keinen Gefallen, wenn ich jetzt irgendwas poste. Irgendjemand (der ich sein könnte) kommt dann her und sagt:
    - dein Code ist nicht praxisrelevant
    - in C++ würde man das anders machen
    - mit meinem Compiler ist das anders
    - mit meinem Allokator ist das anders / ich hätte dafür nen eigenen Allokator geschrieben
    - ...

    Wieso bist du auf der einen Seite so korrekt und auf der anderen Seite wieder nich? Warum ist es dein unbrauchbares Fallbeispiel?

    - Du kannst anscheinend nicht perfekt mit deinem Compiler umgehen
    - Die Zeitmessung, die du verwendest, ist fürn Arsch
    - Dein Beispiel ist nicht so praxisrelevant. Ich berechne nicht ständig PI

    Es gibt so viele Möglichkeiten. Standard C++ fordert strikt IEEE konforme Berechnungen, Java nicht. Der JIT-Compiler kann dadurch Optimierungen durchführen, die der C++ Compiler hier vielleicht grad nicht macht. Die Liste der möglichen Umstände ist endlos. Java ist hier möglicherweise vielleicht gerade schneller, bei was anderem ist es wieder anders rum.

    Normal hätte man doch vermuten müssen, dass C++ schneller ist, allein schon weil es keine "Virtuelle Maschiene" hat.

    Ich vermute das nicht pauschal.

    Optimieren musst du über Mathematik, über Datenstrukturen. Mit nem Wechsel von Java auf C++ oder umgekehrt holst du nicht das selbe raus.



  • kurze ergänzung zu Optimizers Post, dem ich vollkommen zustimme:

    im Prinzip vergleicht der Code lediglich die implementierung von sqrt und pow. Die Schleife ist ja absolut trivial.



  • Optimizer schrieb:

    Es gibt so viele Möglichkeiten. Standard C++ fordert strikt IEEE konforme Berechnungen, Java nicht. Der JIT-Compiler kann dadurch Optimierungen durchführen, die der C++ Compiler hier vielleicht grad nicht macht.

    Einspruch:

    Gerade bei Dingen wie Sinusberechnungen, Cosinusberechnungen usw. hat Java bisher eher auf Genauigkeit als auf Geschwindigkeit gesetzt. Teilweise werden diese Funktionalitäten in Software nachgebaut, weil die Hardwarehersteller es nicht so genau mit der Genauigkeit nehmen. Die Behauptung, dass Java nicht so sehr auf die Genauigkeit achtet, ist also einfach falsch. (Wobei sich das in Zukunft möglicherweise ändern könnte, was IMHO durchaus gut ist: Vergleicht mal die Performance der trigonometrischen Funktionen von (Sun's) Java und einer C++ Implementierung).



  • IMHO ist dieser Grundsatz inzwischen nicht mehr so ganz gültig. Seit strictfp wird standardmäßg nicht IEEE-konformer Code generiert.
    Ok, bei Sachen wie sin weiß ich es nicht. Da ist die Spezifikation eindeutig.
    Aber Prozessoren kennen ja zum Beispiel Befehle wie multiply-add, die nicht dem IEEE Standard entsprechen. Die benutzt der JIT-Compiler AFAIK standardmäßig.



  • Ok, vielleicht hab ich was falsch verstanden. Betrifft strictfp jetzt nur Überläufe?

    Java Language Specification schrieb:

    It follows that an expression is not FP-strict if and only if it is not a compile-time constant expression and it does not appear within any declaration that has the strictfp modifier.

    Within an FP-strict expression, all intermediate values must be elements of the float value set or the double value set, implying that the results of all FP-strict expressions must be those predicted by IEEE 754 arithmetic on operands represented using single and double formats. Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow.



  • Java ist fast immer schneller als C++, nur Swing nicht.



  • Welchen C++ Compiler hast du denn benutzt? OK, VC++ .NET... ist es die 2003er Version? Ist es die Standard-Version oder die Pro-Version?

    Java hat ja (muß man ja sagen) einen Vorteil: der Hotspot kann zur Laufzeit den Code optimieren, und bei solchen Dingen kann ich mir einen Speedvorteil vorstellen.

    Ich habe aber auch in 5 Jahren Java-Erfahrung festgestellt, das vieles in Java grotten langsam ist. Ich sage nur XSLT-Verarbeitung, der Horror!

    Aber auch C++ schläft nicht und MS will ja mit VC++2005 so ein neues intelligentes Compile- und Link-Verfahren raus bringen, das C++ nochmal deutlich in der Performance pushen soll. Leider habe ich den langen englischen Text zu dem Verfahren nicht ganz verstanden... hat sich aber spektakulär gelesen. 😉



  • Es gibt so viele Möglichkeiten. Standard C++ fordert strikt IEEE konforme Berechnungen, Java nicht. Der JIT-Compiler kann dadurch Optimierungen durchführen, die der C++ Compiler hier vielleicht grad nicht macht.

    Jup, daran liegt es. mit dem gcc 3.4 ohne -ffast-math: etwas über 5 Sekunden, mit -ffast-math 'ne knappe halbe Sekunde auf meinem System. Java 1.5 braucht etwas über 3.


Anmelden zum Antworten