sin und cos bei hohen Werten extrem langsam

  • Themenstarter Themenstarter wissenhungriger Gast
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
W

wissenhungriger Gast

Gast
Hi, ich bin gerade am durchtesten mehrerer Sprachen um ein Gefühl dafür zu bekommen. Ich habe testweise (weil das so in der Art bald auf mich zukommen wird) einen kleinen unrepäsentativen Benchmarktest durchgeführt.

So sehen am Ende auf meiner alten Möhre (winxxppro svp 1GBRam Pentium 4 2.66 MHz) die Ergebnisse aus:

Delphi: 8,6 Sekunden (erster Durchlauf 10Sek)
Java 1.6: 80 Sekunden!! (erstellt mit der netbeans 5.5.1 IDE)
c# : 9 Sekunden
purebasic: 8 Sekunden
Blitzmax: 11 Sekunden

so sieht der Java-Code aus, zumindest der wichtige Algo-Teil:

Getestet habe ich mit 10000 (zehntausend) Clients.

Code:
    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        long Anzahl, Iterationen;
        double Sekunden, Minuten, Stunden, DauerMsec;
        long EndTime, NewTime;
        double x=0,y=0,z=0;
            

            EndTime = System.currentTimeMillis();
            Anzahl = Long.parseLong(jTextField1.getText());
            Iterationen = ((Anzahl-1)*Anzahl/2);
            jTextField2.setText(Long.toString(Iterationen));
            jTextField2.repaint();
            jTextField3.setText( "... am rechnen ...");
            jTextField3.repaint();

            for (long i = 0; i < Iterationen; i++)
            {
                y = Math.sin(i);
                x = Math.cos(y);
                z = x * y;
            }
            NewTime = System.currentTimeMillis();
            DauerMsec = (NewTime -EndTime);
            jTextField3.setText(Double.toString(DauerMsec));
            jTextField4.setText(Double.toString(DauerMsec/1000));
            jTextField5.setText(Double.toString(DauerMsec/1000/60));
            jTextField6.setText(Double.toString(DauerMsec/1000/60/60));
            jTextField7.setText(Double.toString(z));
    }

Meine Frage ist jetzt, warum dauert es mit Java sooo lange? Je größer i wird, desto länger braucht es.
Habe ich einen Fehler gemacht? Wie kann man sin und cos optimieren, kann ich für die langsamen Berechnungen auf c oder c++ ausweichen?

Im Endeffekt, soll das Teil sein eines Programms, das auf einen Server laufen soll. Die Aufgabenverteilung wird sein 1. viele sin/cos Berechnungen 2. viele Pakete an vielen Clients schicken 3. Datenbankzugriff.

Und bitte keine Flames oder so was, nur nackte Aufklärung, Java gefällt mir so oder so, auch wenn ich momentan den Weg über Processing gehe und pur Java da einbaue wo ich es brauche.

Danke!

Phil
 
Edit: habs nochmal ausgeführt, braucht sogar 88 Sekunden. Habe mal beim compilieren -server angegeben , hat aber nichts gebracht.
 
Edit 3 😉

Hab da noch was weiter geforscht und raus gefunden, dass wohl Java am besten ist bei den Berechnungen zwischen-PI/4 und +Pi/4, also ich flugs den Code geändert und Zack nur noch 9 Sekunden, na das ist doch anehmbar, auch wenn ich dann alles in 45 Grad Teile unterteilen muss. Oder gibts da noch bessere Lösungen?? Sollte wohl endlich schlafen gehn, muss um sieben raus 😉

Code:
    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        long Anzahl, Iterationen;
        double Sekunden, Minuten, Stunden, DauerMsec;
        long EndTime, NewTime;
        double x=0,y=0,z=0;
        double jo1 = -1*Math.PI/4;
        double jo2 = Math.PI/4;
        

            EndTime = System.currentTimeMillis();
            Anzahl = Long.parseLong(jTextField1.getText());
            Iterationen = ((Anzahl-1)*Anzahl/2);
            jTextField2.setText(Long.toString(Iterationen));
            jTextField2.repaint();
            jTextField3.setText( "... am rechnen ...");
            jTextField3.repaint();
            double jo3 = 2*jo2/Iterationen;
            double j=jo1;
            for (long i = 0; i < Iterationen; i++)
            {
                y = Math.sin(j);
                x = Math.cos(j);
                z = x * y;
                j=j+jo3;
            }
            NewTime = System.currentTimeMillis();
            DauerMsec = (NewTime -EndTime);
            jTextField3.setText(Double.toString(DauerMsec));
            jTextField4.setText(Double.toString(DauerMsec/1000));
            jTextField5.setText(Double.toString(DauerMsec/1000/60));
            jTextField6.setText(Double.toString(DauerMsec/1000/60/60));
            jTextField7.setText(Double.toString(z));
    }
 
vielleicht teste ich das heute auch noch mal,
ein Hinweis vorweg:
die Anzeige
jTextField2.setText(Long.toString(Iterationen));
jTextField2.repaint();
jTextField3.setText( "... am rechnen ...");
jTextField3.repaint();

dürfte nicht klappen oder doch?
normalerweise blockiert die GUI bis zum Ende der actionPerformed() falls du die nicht bereits in einen eigenen Thread gelegt hast,
das wäre nämlich die Standardlösung
 
ja, das scheint sehr deutlich,
ich habe das ganze mal in ein normales main-Programm gesteckt

Code:
public class Test2
{

    public static void main(String[] args)
    {
        long time = 0;
        int number = 10000000;
        double step = (Math.PI / 4.) / number;

        time = System.currentTimeMillis();
        for (long i = 0; i < number; i++)
        {
            Math.sin(i);
        }
        System.out.println("time : " + (System.currentTimeMillis() - time));

        time = System.currentTimeMillis();
        for (long i = 0; i < number; i++)
        {
            double a = (i / number) * step;
            Math.sin(a);
        }
        System.out.println("time : " + (System.currentTimeMillis() - time));


        for (int i = 0; i < 11; i++)
        {
            double a = 0;
            time = System.currentTimeMillis();
            for (long j = 0; j < number; j++)
            {
                a += step;
                Math.sin(a);
            }
            System.out.println("time : " + (System.currentTimeMillis() - time + ", step: " + step + ", max: " + a));
            step *= 10;
        }


    }

}

Ausgabe:
time : 10949
time : 1205
time : 782, step: 7.853981633974483E-8, max: 0.785398163255418
time : 1689, step: 7.853981633974483E-7, max: 7.853981633943045
time : 1971, step: 7.853981633974484E-6, max: 78.53981634042253
time : 1798, step: 7.853981633974484E-5, max: 785.398163230516
time : 1799, step: 7.853981633974484E-4, max: 7853.981633281307
time : 1940, step: 0.007853981633974483, max: 78539.8163257414
time : 2080, step: 0.07853981633974483, max: 785398.1632299493
time : 10668, step: 0.7853981633974483, max: 7853981.6358696185
time : 11951, step: 7.853981633974483, max: 7.853981634106919E7
time : 12138, step: 78.53981633974483, max: 7.853981634695207E8
time : 12279, step: 785.3981633974483, max: 7.853981635477473E9


die Umrechung von int nach double im Programm ist kein großer Aufwand (zweiter Test),

interessant ist die Untersuchung mit verschiedenen step-Größen,
muss gar nicht im Bereich von PI verlaufen, auch bis 10000fach darüber geht's noch einigermaßen,
dann bei einer 10er-Potenz auf einmal ein großer Bruch in der Laufzeit,
darüber wiederum egal, was das wohl soll.. 😉
 
hatte die Info aus hier: forums.java.net/jive/message.jspa?messageID=35756

Hi,
I'm a JVM engineer for Sun and for Mustang I worked on improving trig and transcendental performance. Right now SIN/COS/TAN/LN/LN10/SQRT/ABS are all intrinsified to call directly to hardware. Try a new Mustang build and see what kind of performance improvements you're seeing. Also for trig functions, the Intel hardware is extremely fast for -pi/4 to +pi/4 but slows down outside of these ranges (due to argument reduction). If you can keep your values between those ranges you should see a nice improvement as well.


ich habe jetzt die neue Version in BlitzMax ausprobiert und siehe...Zeit bleibt gleich ???:L da ist jetzt sogar Java noch schneller, das isn Ding wa? :applaus:

Die Kunst ist wirklich heraus zu finden wie man was optimieren kann.

@SlaterB, hast recht, habe das so wie in c# geschrieben und da geht das 🙂 Ich habe bisher noch nicht viel mit Java gemacht, es dauerte mir einfach zu lange, bis ich was grafisches auf die Beine gestellt hatte, aber jetzt mit Processing macht das richtig Spaß, Java in verdauungsgerechten Scheiben quasi 😀

Aber ich werde das mit dem Threading mal angehen ^^
 
ohne jetzt irgend etwas andeuten zu wollen aber ich habe mal eben den code nach Processing rüber geholt...
Ich hoffe ihr sitzt alle ... 8,5 Sekunden!!!!! und somit so schnell wie Delphi und purebasic, irre! und das von ehemals 90 Sekunden :autsch:

Ach ja hier der Code aber ist ja klar, da ja auch Java mit der Processing Api. Mensch ist das geil, da lohnt sich ja das Kopf zerbrechen über Auslagerung in C oder Assembler gar nicht :bae:
Code:
/*

  Iterationen BenchmarkTest (2007/08/19)

*/

void draw(){
long anzahl = 10000;
long iterationen = 0;
double DauerMsec = 0;
double x=0,y=0,z=0;
long altZeit,neuZeit;
double jo1 = -1*Math.PI/4;
double jo2 = Math.PI/4;
iterationen = ((anzahl-1)*anzahl/2);
// String sf = nf(iterationen,3,5);
println(String.valueOf(iterationen));
double jo3 = 2*jo2/iterationen;
double j=jo1; 
altZeit = millis();
for (long i=0;i<=iterationen;i++)
{
                y = Math.sin(j);
                x = Math.cos(j);
                z = x * y;
                j=j+jo3; 
}
neuZeit = millis();
DauerMsec = neuZeit-altZeit;
println("Zeit in Millis  : " + String.valueOf(DauerMsec));
println("Zeit in Sekunden: " + String.valueOf(DauerMsec/1000));
exit();
}
 
sin() und cos() sind im übrigen native Methoden. Es ist also an dieser Stelle nicht Java selbst so schnell. 😉
 
Java ist Schuld, Windoof dran zu lassen 😉
(edit: habe ' Es ist also an dieser Stelle nicht Java selbst so langsam' gelesen)
 
hmmm, mag ja alles sein, aber BlitzMax kompiliert mit MinGW, selbst eine Auslagerung der sin und cos Funktionen in reinem C mit der neuesten MinGW Version hat nichts gebracht, also muss Java auch eine 'Teilschuld' an diesem netten Resultat haben.
 
Offenbar hat Sun einfach nur ziemlich schnelle Algorithmen geschrieben, aber die sind halt nicht in Java-Code implementiert, sondern es wird nativer Code aufgerufen.
 
übrigens, nette sache, wenn man viele sin/cos dinger für ganzzahlige Gradwerte braucht: einfach ein final double[360] Array (als Feld) erstellen und jeden index mit dem sinus/cosinus Wert des entsprechenden indexes speichern. das ergibt einen gewaltigen performanceboost!
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben