lange Zahlenreihe ausgeben

  • Antworten:28
fileerror
  • Forum-Beiträge: 116

17.11.2014, 14:40:32 via Website

Hallo,

ich habe in letzter Zeit mal probiert, mich mit der App-Entwicklung für Android vertraut zu machen. So als kleinen Anfangstest habe ich eine App geschrieben, die Primzahlen in einem bestimmten Wertebereich ausrechnet und ausgibt. Nun bin ich auf eine Problem bei der Ausgabe gestoßen, bei dem ich nicht weiterkomme. Ich habe da ein TextView und in dieses schreibe ich mit textview1.append(String.valueOf(primzahl)) in der Schleife jede neu berechnete Zahl. Mein Problem ist jetzt, dass die Berechnung schon bis 10000 eine Ewigkeit dauert und die App teilweise abstürzt. Wenn ich die Ausgabe so schreibe: textview1.setText(String.valueOf(primzahl)), dann rechnet es bis zu einer Million in 3 sec. hoch, nur steht dann halt am Ende nur die letzte berechnete Zahl im Textfeld. Dann habe ich es so probiert um im Vorfeld schon alles zusammenzufügen:
String primstring = primstring + ", " + String.valueOf(primzahl). Und dann halt nach der Berechnung textview1.setText(String).
Und wieder dauert alles eine Ewigkeit. Das bedeutet ja, dass das Problem beim zusammenfügen der Zahlen entsteht, nur was soll ich da anders machen? Ich wäre sehr dankbar, wenn mir jemand auf die Sprünge helfen könnte.

Gruß fileerror

Antworten
Sven R.
  • Forum-Beiträge: 1.904

17.11.2014, 14:48:28 via App

http://openbook.galileocomputing.de/javainsel9/javainsel_04_004.htm#mjc49a6b30f15f92cfaa850a38756238c9
StringBuilder sind ein enormer Performance - Boost gegenüber einfach nur string1 + string2.

 instanzVomStringBuilder.append(string1).append(string2);
String fertigerString = instanzVomStringBuilder.toString();

— geändert am 17.11.2014, 14:50:12

Wenn dir mein Beitrag gefällt, kannst dich einfach mit dem 👍 "Danke"-Button auf der Website dieses Forums bedanken. 😀

Why Java? - Because I can't C#

Antworten
fileerror
  • Forum-Beiträge: 116

17.11.2014, 15:02:06 via Website

ah danke, das werde ich dann mal testen.

Antworten
fileerror
  • Forum-Beiträge: 116

18.11.2014, 00:12:27 via Website

So ich hab das mit dem StringBuilder jetzt mal getestet und: es ist wirklich ein Unterschied wie Tag und Nacht!
Die Verzögerung bei der Ausgabe bis 1 Mio. hat sich von ewig auf ca 20 sec. reduziert. Nur leider dauert die eigentliche Berechnung nur 3 sec.
Warum kann es nicht wie in der Java-Console ohne Zeitverzögerung ausgegeben werden. Gibt es keine Möglichkeit jede berechnete Zahl sofort auszugeben?

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

18.11.2014, 04:46:08 via App

Hallo fileerror,

du musst bedenken das die Ressource auf einen Device knapp sind. Auf einem PC hast du mit Sicherheit einen größeren RAM Speicher und einen schnelleren CPU. Dadurch geht es in der Java-Console um einiges schneller.

— geändert am 18.11.2014, 04:46:19

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

Antworten
Stefan
  • Forum-Beiträge: 1.560

18.11.2014, 07:55:29 via App

Ich weiß ja nicht, wie du die Primzahlen überprüfst, aber ne nach Verfahren ist es ein extremer Aufwand

ALLERGIKERINFO:
Beiträge können Spuren von Humor, Ironie, Sarkasmus und Erdnüssen enthalten.

Antworten
fileerror
  • Forum-Beiträge: 116

18.11.2014, 10:38:17 via Website

Also erstmal danke für die Antworten. Ich habe mir da echt Gedanken gemacht und einen denke ich ziemlich flotten Algorithmus geschrieben. Jetzt
habe ich zum Spaß mal den Stringbuffer auskommentiert und lasse immer nur die aktuell berechnete Zahl zu einem String machen. Das heißt, am Ende steht dann nur die letzte berechnete Zahl im TextView und: mein Handy rechnet in 3,7 sec. bis 1 Mio. hoch - mit Stringbuffer braucht es über 25 sec. Also ist die Ausgabe das langsamste an der ganzen Prozedur. Das ist echt traurig :( Wenn ich direkt alles in das TextView schreiben lasse,
dann dauert es schon bis 100.000 ewig.

Antworten
Sven R.
  • Forum-Beiträge: 1.904

18.11.2014, 13:39:21 via App

Dauert denn das toString() so lange oder das append()?

Wenn dir mein Beitrag gefällt, kannst dich einfach mit dem 👍 "Danke"-Button auf der Website dieses Forums bedanken. 😀

Why Java? - Because I can't C#

Antworten
fileerror
  • Forum-Beiträge: 116

18.11.2014, 15:58:23 via Website

Das ist schwer zu sagen ob es am Ende das toString() der ewig langen Zahlenreihe ist oder das append() oder beides. Am eifachsten wäre es, jede Zahl direkt ins TextView auszugeben, aber leider geht das scheinbar nicht. Wenn ich textview1.append(String.valueOf(primzahl)) benutze, dann dauert es auch eine Ewigkeit, genau wie beim String + String, und alles wird erst komplett durchlaufen, bevor dann alle Zahlen auf einmal ausgegeben werden. Also scheint da intern auch nur String + String gerechnet zu werden.

Antworten
fileerror
  • Forum-Beiträge: 116

18.11.2014, 16:20:39 via Website

OK es ist hauptsächlich das toString(). Wenn ich das am Ende weg lasse, komme ich auf knapp 5 sec. runter.

Antworten
Sven R.
  • Forum-Beiträge: 1.904

18.11.2014, 20:16:30 via App

Ich kenne keine andere Lösung. Vielleicht wer anderes?

Wenn dir mein Beitrag gefällt, kannst dich einfach mit dem 👍 "Danke"-Button auf der Website dieses Forums bedanken. 😀

Why Java? - Because I can't C#

Antworten
Fabian
  • Forum-Beiträge: 144

18.11.2014, 21:31:42 via App

Also ich weiß ja nicht, wo genau du toString() aufrufst aber diese Zahlen sind in der Tat sehr realistisch. Du musst auch bedenken, dass Strings sogenannte Immutables sind und damit unveränderlich. Das bedeutet für dein Programm, dass es mehrere 1000 von Strings erzeugen muss. Dann kommt die Textausgabe in die TextView hinzu, was auch nicht gerade sehr schnell ist. Wieso errechnet du nicht gleich alle Primzahlen die du brauchst und hängst diese alle aneinander um sie dann in einen String zu konvertieren und dann auszugeben?

Grüße Fabian!

Antworten
Martin
  • Forum-Beiträge: 756

18.11.2014, 21:53:47 via App

Ich würds genauso wie Fabian machen...

Antworten
Georg C.
  • Forum-Beiträge: 235

18.11.2014, 23:56:15 via Website

@Stefan

Ich weiß ja nicht, wie du die Primzahlen überprüfst, aber ne nach
Verfahren ist es ein extremer Aufwand

boolean isprim;
final int ZAHL=100000;
    for (int n=2;n<=ZAHL;n++) {
    isprim = true;
        for (int i=2;i<n;i++) {
        if ((n % i) == 0) { // Falls der Rest 0 ist, haben wir einen Teiler von n gefunden...
            isprim = false;
            break;    
        } 
    }
    if (isprim)
    System.out.println(n);
}

Was soll da so kompliziertes sein?
Außerdem; - dass (oder ähnliches) Code, findet man in jeden 3 Java Buch.
Klar es konnte man das Code noch etwas optimieren.

@fileerror
denk bitte daran, dass alle aufwendige Rechnerarbeiten, ..... in einen Thread reingehören.
Also nicht NUR in der Java, werden Rechnerlasten, ..... in einen separaten Thread ausgelagert.
Soll es mit der GUI Komponenten gearbeitet werden, - (UI- Thread Kommunikation), verbleibt dir nur der AsynTask.

LG
Georg

Sorry für Gramatik & Stilistik Fehler.

Antworten
fileerror
  • Forum-Beiträge: 116

19.11.2014, 14:34:30 via Website

@Fabian

denke ich mache es ja so, ich füge alle zahlen mit add(primzahl) zum stringBuffer und am Ende gebe ich es dann mit toString aus.

Antworten
fileerror
  • Forum-Beiträge: 116

19.11.2014, 14:39:24 via Website

@ Georg

also ich hab das mal auf meinem Laptop bis 1 Mio. hochzählen lassen und da braucht dein Code 4 Min 10 Sekunden. Meiner ist in 3 Sekunden fertig - also ich denke ich habe da schon bissel Aufwand betrieben. ;)

Mit Threads habe ich mich noch nicht beschäftigt. Da kann man die Aufgaben auf mehrere Kerne verteilen, richtig? Das würde sicher auch helfen.

Gruß fileerror

Antworten
Stefan
  • Forum-Beiträge: 1.560

19.11.2014, 15:34:36 via Website

Georg C.

Was soll da so kompliziertes sein?
Außerdem; - dass (oder ähnliches) Code, findet man in jeden 3 Java Buch.
Klar es konnte man das Code noch etwas optimieren.

Hallo Geog C.,

dieser Algorithmus (nicht deine Programmierung vom Algorithmus) ist einfach eine Katastrophe, da er hochgradig ineffizient ist.

Bei jedem Durchgang werden n-1 Divisionen durchgeführt, da überprüft wird, ob die Division mit jeder Zahl kleiner n einen Rest von 0 ergibt.
Wenn man sich das ganze mal etwas mathematisch überlegt, dann kommt man seh schnell drauf, dass die zweite Schleife nur bis zur Wurzel von n gehen muss, alles was darüber kommt, entweder ein Produkt aus kleineren Zahlen ist, oder nicht meh 0 ergeben kann.

Wenn du dir das ganze mal am Beispiel 100 anschaust. Die Wurzel von 100 ist 10.
Wenn du anfängst mit deiner Schleife (unabhängig vom Rest), kommen folgende Egebnisse 50 - 33,.. - 25 - 20 - 16,... - 14,... - 12,5 - 10 , jetzt bist du an der magischen Grenze Wurzeln 100 und ab jetzt wird es nur noch kleiner, d.h. diese Divisionen hast du schon abgearbeitet. nächste ist dann 9,...

Vielleicht ist das ganze jetzt nicht so toll erklärt, aber dafür gibt es bestimmt im Internet schönere Erklärungen.

Der genannte Alogrithmus von dir führt natürlich zum richtigen Ergebnis, führt aber insgesamt fast 5 * 10^9 (5 Milliarden!) unnötige Divisionen durch!

— geändert am 19.11.2014, 15:40:56

ALLERGIKERINFO:
Beiträge können Spuren von Humor, Ironie, Sarkasmus und Erdnüssen enthalten.

Antworten
fileerror
  • Forum-Beiträge: 116

19.11.2014, 16:12:04 via Website

richtig! und wenn man durch 2 geteilt hat und es ging nicht, braucht man nicht mehr durch 4, 6, 8 usw. bei 3 dann nicht mehr durch 6, 9 usw.

noch was komisches: wenn ich "textView.append(stringBuiler.toString())" benutze ist das 12 Sekunden schneller als textView.setText(stringBuilder.toString())" Das soll einer verstehen. (25 zu 37 Sekunden)

Antworten
Stefan
  • Forum-Beiträge: 1.560

19.11.2014, 16:13:51 via Website

Genau, das kommt dann noch zur weiteren Optimierung dazu, kleinster gemeinsamer Teiler überprüfen usw.

Der von mir gebrachte Vorschlag lässt sich aber denke ich am einfachsten einbauen, man mus ja nur die Wurzel ergänzen.

ALLERGIKERINFO:
Beiträge können Spuren von Humor, Ironie, Sarkasmus und Erdnüssen enthalten.

Antworten
fileerror
  • Forum-Beiträge: 116

19.11.2014, 16:17:03 via Website

Da hast du recht. Ich hab halt alles eingebaut. Wollt mal sehen, ab ich das hinbekomme, so als Noob ;)

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

19.11.2014, 16:19:28 via App

Ganz einfach append heißt hinzufügen und setText ersetze den Text, Schlussfolgerung hinzufügen geht schneller da der string nicht erneut eingelesen wird.

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

Antworten
fileerror
  • Forum-Beiträge: 116

19.11.2014, 16:21:52 via Website

hmm aber das TextView ist doch leer, so oder so :(

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

19.11.2014, 18:54:06 via App

Ja schon aber die TextView selber ist ja "dumm" und weis zu dem Zeitpunkt als du apprend in Editor eingibst noch nicht, dass sie leer ist.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Fabian
  • Forum-Beiträge: 144

19.11.2014, 22:55:53 via App

Du hast mich nicht richtig verstanden. Also mal abgesehen davon dass dir noch so einige Java Kenntnisse fehlen, auch was Threads angeht, suche mal nach der Klasse BigInteger falls du die Zahlen wirklich alle hintereinander ausgeben willst. Ansonsten erzeugst du eine Konstante vom Typ String mit einem Leerzeichen und fügst diesen nach jeder Primzahl ein. In diesem Fall wird dann nur ein String erzeugt und die JVM nicht mit Strings bombardiert.

Grüße Fabian!

Antworten
Georg C.
  • Forum-Beiträge: 235

19.11.2014, 23:30:18 via Website

Hallo Stefan,

.... dieser Algorithmus ... ist einfach eine Katastrophe .... ...
führt aber insgesamt fast 5 * 10^9 (5 Milliarden!) unnötige Divisionen
durch! ...

UPS! - Sorry - .... und ich habe gedacht, dass mein Rechner immer langsamer wird!
... (silly)
Danke für die ausführliche Erklärung.

LG
Georg

Sorry für Gramatik & Stilistik Fehler.

Antworten
Stefan
  • Forum-Beiträge: 1.560

20.11.2014, 13:24:31 via Website

Kein Problem, wie gesagt, allein durch hinzufügen der Wurzel solltest du schon einen erheblichen Leistungsgewinn erzielen. Weitere Optimierungen sind natürlich auch noch möglich.

ALLERGIKERINFO:
Beiträge können Spuren von Humor, Ironie, Sarkasmus und Erdnüssen enthalten.

Antworten
fileerror
  • Forum-Beiträge: 116

20.11.2014, 15:40:03 via Website

@Fabian

Eigentlich wollte ich nur alle Zahlen, so wie sie kommen, ausgeben lassen. Aber das funktioniert so leider nicht. Man muss immer erst alle speichern und dann am Ende ausgeben. Mit der Stringbuilder-Lösung kann ich eigentlich leben, da ich die Zeit so schon wahnsinnig reduzieren konnte. Mich ärgert halt nur, daß die Ausgabe mehr Zeit beansprucht, als die Berechnung.

Antworten
Fabian
  • Forum-Beiträge: 144

20.11.2014, 16:35:16 via App

Das liegt zum einen daran, dass die Berechnungen mit primitiven Datentypen durchgeführt werden, was sehr viel schneller ist und die Ausgabe mit Objekten arbeitet. Zum anderen kann ich mir vorstellen dass du alles im Main(UI) Thread abarbeitest und keinen separaten erzeugt hast.

— geändert am 20.11.2014, 16:36:43

Antworten
fileerror
  • Forum-Beiträge: 116

20.11.2014, 17:29:47 via Website

Ja so ist das. Das werd ich wohl mal ändern müssen. ;)

Antworten