Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Ein bisschen InlineAssembler hilfe :) (https://www.delphipraxis.net/143528-ein-bisschen-inlineassembler-hilfe.html)

Spiderpig_GER_15 17. Nov 2009 18:31


Ein bisschen InlineAssembler hilfe :)
 
Hallo DP,

ich bin grade dabei folgendes:
Delphi-Quellcode:
I: integer;
n: double;
Zahl: double;
  while Zahl < i do
  begin
    Zahl:= Zahl +1/n;
    n:= n+1;
  end;
auf Zeit zu trimmen...
und was geht schneller als etwas ASM?

Ist hier jemand willig und in der Lage mir das zu übersetzten, es ist mit hoher dankbarkeit zu rechnen:D

Müsste machbar sein, oder?

Gruß Spiderpig

Zacherl 17. Nov 2009 18:36

Re: Ein bisschen InlineAssembler hilfe :)
 
Ich denke mal bei solch trivialen Operationen bringt es keinen Geschwindigkeitsvorteil, wenn man sie in Assembler umsetzt.

Spiderpig_GER_15 17. Nov 2009 18:38

Re: Ein bisschen InlineAssembler hilfe :)
 
garkein ganz kleines bisschen?

immerhin wird diese schleife über: 40427833547 mal ausgeführt...

Neutral General 17. Nov 2009 18:41

Re: Ein bisschen InlineAssembler hilfe :)
 
Hi,

Das ließe sich zwar übersetzen, aber das würde wie schon gesagt eher keinen Geschwindigkeitsvorteil bringen.. eher das Gegenteil ;)

Spiderpig_GER_15 17. Nov 2009 18:48

Re: Ein bisschen InlineAssembler hilfe :)
 
ok, bin mittlerweile aber trotzdem neugierig geworden wie das aussehen könnte, wenn es jemand weiß, nur zu

dankeschön,

Spideprig

PS: gibts sonstige Möglichkeiten, dass Programm schneller werden zu lassen (kann man sich mehr Ressourcen klauen?) immerhin sind nur 50% meiner CPU ausgelastet (Quelle Taskmanager)?

mleyen 17. Nov 2009 19:25

Re: Ein bisschen InlineAssembler hilfe :)
 
Lass es über die Grafikkarte laufen. (soll schneller gehn :lol: )

Ich weißt zwar nicht wie es geht, aber es würde mich auch mal interessieren. :duck:

Medium 17. Nov 2009 19:47

Re: Ein bisschen InlineAssembler hilfe :)
 
Hmm, du weisst schon, dass du ab irgendwann da präzisionsbedingt nur noch Nullen addierst, oder?

Und auf der GraKa würde DAS hier nix bringen. Zum einen können erst eine Hand voll der neusten überhaupt mit Double-Precision arbeiten, zum anderen sind die nur fix wenn man einProblem sehr gut parallelisieren kann. Das da oben ist mal sowas von sequenziell, da müsste man wenn schon einen parallelisierbaren Ersatz-Algo für aufstellen (falls es den gibt).

uoeb7gp 17. Nov 2009 19:50

Re: Ein bisschen InlineAssembler hilfe :)
 
Also, ASM ist nicht gleich ASM.
Für i386 und MMX wirds nicht viel bringen, da der Compiler hier schon gut optimiert.
Was steht den zur Verfügung?

IA32, SSE, SSE2, SSE3 ??? Multicores ??? 32+||64Bit ???

Wenn für alle CPU's und instructions ASM codiert werden soll, ist das schon ein gewisser Aufwand!

Das Ding geht dann schon ab wie eine Rakete. 600% + (Amd64 SSE3) müssten locker drin sein.

lg.

Medium 17. Nov 2009 19:54

Re: Ein bisschen InlineAssembler hilfe :)
 
Auch SSE ist nur bei Parallelisierung brauchbar (Bei Google suchenSIMD). Was soll der Code eigentlich bringen? Warum will man eine bereits bekannte Zahl so annähern? (Kettenbruchdarstellung wäre jetzt das einzige was mir so einfiele, die wird mit Floats bei sehr langen Ketten dann aber halt auch eher schwammig.)

uoeb7gp 17. Nov 2009 20:01

Re: Ein bisschen InlineAssembler hilfe :)
 
Naja, vielleicht gehts um einen Bench?
Gewettet wurde ja schon um vieles!! "g"

Spiderpig_GER_15 wirds uns hoffentlich verraten!

lg.

himitsu 17. Nov 2009 20:11

Re: Ein bisschen InlineAssembler hilfe :)
 
Delphi macht etwa das daraus
Delphi-Quellcode:
00461AF3 EB1F            jmp @@Loop
@@Start:
// Unit1.pas.32: Zahl:= Zahl +1/n;
00461AF5 D905381B4600     fld 1
00461AFB DC3424           fdiv &n
00461AFE DC442408         fadd &Zahl
00461B02 DD5C2408         fstp &Zahl
00461B06 9B              wait
// Unit1.pas.33: n:= n+1;
00461B07 DD0424           fld &n
00461B0A D805381B4600     fadd 1
00461B10 DD1C24           fstp &n
00461B13 9B              wait
@@Loop:
// Unit1.pas.30: while Zahl < i do
00461B18 DB442410         fild &i
00461B1C DC5C2408         fcomp &Zahl
00461B20 9B              wait
00461B21 DFE0             fstsw ax
00461B23 9E              sahf
00461B24 77CF            jnbe @@Start
Eine Optimierung, welche mir einfällt ... kann man das n denn nicht auch als Integer auslegen?
Delphi-Quellcode:
// Unit1.pas.33: n:= n+1;
00461B07 DD0424           fld &n
00461B0A D805381B4600     fadd 1
00461B10 DD1C24           fstp &n
00461B13 9B              wait
Hier würde ja alles in einen winzigen Befehl (INC &i) reinpassen und das dan auch noch sofort und ohne warten auf die FPU.

Mit der ASM-Programmierung der Fließkommaeinheit kenn ich mich nicht grade aus, aber vielleicht kann man da ja die Zahl gleich da drinne lassen und nicht immer rein- und wieder rauskopieren.
Wenn man das n als Integer hätte, dann würde in der FPU ja nur vorranging mit Zahl gerechnet, wärend n, zusammen mit i womöglich sogar nur in den Registern rumgammeln könnte.


PS: wir hatten hier schon ein paar Mal, daß die hochoptimierten (Versuche von Menschen) ASM-Codes wesentlich langsamer oder wenigstens/zumindestens genauso schnell waren, wie die optimierten Delphi-Codes aus 'nem Pascal-Compiler.

Neutral General 17. Nov 2009 20:14

Re: Ein bisschen InlineAssembler hilfe :)
 
Zitat:

Zitat von mleyen
Lass es über die Grafikkarte laufen. (soll schneller gehn :lol: )

Ich weißt zwar nicht wie es geht, aber es würde mich auch mal interessieren. :duck:

Hatte mich gerade drangesetzt. Aber die FPU hat mich geärgert. Ich weiß zwar jetzt wies geht aber jetzt hab ich keine Lust mehr :stupid:

sx2008 17. Nov 2009 20:21

Re: Ein bisschen InlineAssembler hilfe :)
 
Du berechnest anscheinend eine harmonische Reihe.
Mit der richtigen Näherungsformel kannst du die Laufzeit extrem :zwinker: verringern.

Medium 17. Nov 2009 21:15

Re: Ein bisschen InlineAssembler hilfe :)
 
Ungetestet, und keine Ahnung ob das wirklich schneller ist. Spart ein paar OPs, ob es damit auch cycles spart ist nie so sicher :) Zumindest spart es eine Menge pushes auf den FPU Stack! Auch möglich, dass man den Vergleich mit i noch etwas optimieren kann, ohne die Statusbits erst noch nach AX zu schaufeln. Das wait kann man sich erfahrungsgemäß so gut wie immer sparen. In meinen Handoptimierungen hat es bislang zumindest nie weh getan das einfach ersatzlos zu streichen :twisted:

Delphi-Quellcode:
fild &i
fld &n
fld &Zahl
jmp @@Loop
@@Start:
// Unit1.pas.32: Zahl:= Zahl +1/n;
fld 1
fdiv st(0), st(2)
faddp
// Unit1.pas.33: n:= n+1;
fadd st(1), 1
@@Loop:
// Unit1.pas.30: while Zahl < i do
fcomp st(2)
fstsw ax
sahf
jnbe @@Start

Spiderpig_GER_15 18. Nov 2009 16:14

Re: Ein bisschen InlineAssembler hilfe :)
 
Hi, danke für eure bemühungen :D

Kann es sein, dass die 50% Auslastung daher kommen, dass er meinen Dualcore nicht ausnutzt? (hab 2 * 3,0GHZ) wenn ja, wie kann ich das erreichen? Wäre das ein Ansatz für bessere Ergebnisse?

N kann leider kein integer sein (es ist zwar ganzzahlig, aber wird größer als der Bereich eines Int). Hat Delphi was genaueres auf Lager als double? Vielleicht sollte ich einen Abbruch machen, wenn 1/n = 0 ist, da es dann ja keinen Sinn mehr macht. Wieviel macht eine zusätzliche If Abfrage in einer solchen Schleife aus? Fatal?

Gruß vom Spiderpig,

(achso, der Grund ist eigentlich nur persönliches Interesse, und Anfrage meines Bruders ;) )

Namenloser 18. Nov 2009 16:42

Re: Ein bisschen InlineAssembler hilfe :)
 
Zitat:

Zitat von Spiderpig_GER_15
Hi, danke für eure bemühungen :D

Kann es sein, dass die 50% Auslastung daher kommen, dass er meinen Dualcore nicht ausnutzt? (hab 2 * 3,0GHZ) wenn ja, wie kann ich das erreichen? Wäre das ein Ansatz für bessere Ergebnisse?

Natürlich, wie soll er denn den 2. Kern auch nutzen? Du hast ja nichts parallelisiert.
Zitat:

Zitat von Spiderpig_GER_15
N kann leider kein integer sein (es ist zwar ganzzahlig, aber wird größer als der Bereich eines Int). Hat Delphi was genaueres auf Lager als double? Vielleicht sollte ich einen Abbruch machen, wenn 1/n = 0 ist, da es dann ja keinen Sinn mehr macht. Wieviel macht eine zusätzliche If Abfrage in einer solchen Schleife aus? Fatal?

Es gibt noch den Typ Extended, aber vergiss nicht, dass die Genauigkeit nicht gerade unerheblichen Einfluss auf die Geschwindigkeit hat. Einen Vergleich auf 1/n=0 zu machen, bringt nichts, weil n nie genau 0 wird, sondern einfach immer ungenauer, und das bei jeder Iteration.

Spiderpig_GER_15 18. Nov 2009 16:49

Re: Ein bisschen InlineAssembler hilfe :)
 
extended ist also größer als double? Dann probier ich es mal damit (brauche übrigens nur positive Zahlen).

aber irgendwann ist doch auch aus der letzen 1 eine null geworden?!

Apollonius 18. Nov 2009 16:54

Re: Ein bisschen InlineAssembler hilfe :)
 
Nur wenn n unendlich wird. Warum verwendest du eigentlich kein Int64?

himitsu 18. Nov 2009 16:54

Re: Ein bisschen InlineAssembler hilfe :)
 
Zitat:

Zitat von Spiderpig_GER_15
extended ist also größer als double?

Laut der OH :zwinker: ja.

Single = 4 Byte
Double = 8 Byte (doppelt so groß wie Single)
Extendet = 10 Byte

Allerdings ist das mit den "Größen" bei den Fließkommatypen soeine Sache.

Es muß nicht unbedingt die Größe größer werden, nur weil der Typ größer wird.
Tut es zwar, aber hier kommt es eigentlich mehr auf die nun größere Genauigkeit an.
Genaueres siehe OH.

Und das mit den 50% (bei einem QuadCore wären es nur ~25% :zwinker:)
Bei dir ist halt alles in einem Thread und ein Thread läuft immer nur auf einem Prozessor (gleichzeitig) ... für mehr müßtest du die Beechnung mehrere Threads aufteilen und diese Threads auch noch unterschiedlichen CPUs zuteilen (falls dieses Windows nicht automatisch macht)

Namenloser 18. Nov 2009 16:56

Re: Ein bisschen InlineAssembler hilfe :)
 
Zitat:

Zitat von Spiderpig_GER_15
aber irgendwann ist doch auch aus der letzen 1 eine null geworden?!

Bei Festkommazahlen wäre das so, aber Gleitkommazahlen speichern die Werte als Kombination aus Koeffizient (Mantisse) und Exponent. Den Exponent kannst du einfach immer weiter verringern, ohne dass die Zahl 0 wird. Natürlich wird auch der Exponent theoretisch irgendwann 0, aber das kann dauern. Und während dieser Zeit werden die Werte immer ungenauer, ich schätze, dass der Koeffizient irgendwann pseudo-zufällige Werte annimmt.
Es hat schon seinen Grund, dass man Gleitkommazahlen nie auf 0 prüfen sollte, schon allein deshalb, weil sich 0 auf verschiedene Weisen darstellen lässt. Nicht umsonst gibt es auch die Funktion IsZero() aus der Unit Math.

Bitte schlagt mich nicht, wenn ich jetzt mit meinem Halbwissen irgendwas falsches erzählt habe, aber ich glaube, das ist eifnach eine schlechte Idee. Und dein ursprüngliches Problem kriegst du auf diese Weise garantiert nicht gelöst.

Medium 18. Nov 2009 16:57

Re: Ein bisschen InlineAssembler hilfe :)
 
Bei den 50% liegst du richtig. Weitere Kerne zu nutzen ist aber, wieder ein mal, nur möglich wenn du parallelisieren kannst, wie auch bei der Grafikkarte oder den SIMD Befehlssätzen. Ein einzelner Thread (den dein Programm derzeit wohl nur hat) kann nicht verteilt werden, und eine Aufgabe müsste in Teile zerlegt werden die gleichzeitig verarbeitet werden können. Im Idealfall in so viele Teile wie Cores vorhanden sind, und alle mit ca. gleicher Laufzeit. Dann kannst du Multicores super ausnutzen/lasten, nur ist das hier wie gesagt nicht so möglich. (Wenn man genau wüsste worum es geht, ließe sich evtl. ein zerteilbarer Algo finden, mit genau dem Source wird's jedenfalls nix.)

Genauer als Double (64 Bit) ist nur noch Extended (80 Bit) was native Typen angeht. Dennoch halte ich meine Sinn-Frage aufrecht ;)

Wenn du i übrigens als Int64 nimmst hast du die selbe Genauigkeit wie mit Double. Int64 kann maximal 2^64-1 genau darstellen (*) - ich bin mir fast sicher dass Double schon vorher ganzzahlige Sprünge bei großen Werten aufweist. An spätestens der selben Stelle dürfte dann auch die Division 1/N keine verlässlichen Ergebnisse mehr liefern - eher früher.

Eine zusätzliche if-Abfrage ist mindestens ein "comp" oder "fcomp+statusbits schaufeln" + einem jump mehr, was auf die geringe Menge Code sicherlich gut messbaren Einfluss haben dürfte.

(*) Delphis Int64 ist ja nun leider Vorzeichenbehaftet, so dass nur halb so viele positive Zahlen möglich sind. Ein UInt64 kennt Delphi nicht - zumindest nicht in den Win32 Varianten, bei .NET bin ich unsicher. Auch bin ich nicht auf dem Stand, ob und wie 64er Ints auf der FPU verarbeitet werden können.


Alles in allem ist das gesamte Vorhaben problematisch, und solange es keinen größeren Zusammenhang gibt in dem man das ganze evtl. anders angehen könnte, seine Sache auch kaum wert.


Edit: 4 Postings dazwischen, uiuiui ich werd alt und lahm :cry:


Edit2:
Zitat:

Zitat von NamenLozer
Bitte schlagt mich nicht, wenn ich jetzt mit meinem Halbwissen irgendwas falsches erzählt habe, aber ich glaube, das ist eifnach eine schlechte Idee. Und dein ursprüngliches Problem kriegst du auf diese Weise garantiert nicht gelöst.

Eigentlich war das alles :thumb:

Apollonius 18. Nov 2009 17:04

Re: Ein bisschen InlineAssembler hilfe :)
 
Double ist 64 Bit groß, insofern muss dort aufgrund des Exponenten die Genauigkeit zwangsläufig unter der von Int64 liegen. Extended stellt 64 Bit für die Mantisse bereit, wenn ich mich nicht irre.

himitsu 18. Nov 2009 17:08

Re: Ein bisschen InlineAssembler hilfe :)
 
UInt64 kennt Delphi schon, auch schon D7,
abe rleider gab es da ein Problem, so daß viele UInt64-Operationen auf die Int64-Proceduren übergeben wurde, statt auf die teilweise schon vorhandenen UInt64-Prozeduren.

Seit spätestens Delphi 2006 sollte es da aber keine/kaum noch Probleme mehr geben.


PS: was die "genauen" Ganzzahlen in den Fließkommatypen angeht.
siehe OH > signifikante Stellen
Single = 7-8
Double = 15-16
Extended = 19-20

und 19-20 Stellen haben übrigens auch Int64/UInt64 (nur das Extended nochmal 2 Byte größer ist)

helgew 26. Nov 2009 11:08

Re: Ein bisschen InlineAssembler hilfe :)
 
ein kleiner Vorschlag:

wie oben gesagt, kann man auch mit integerarithmetik arbeiten, dann bietet es sich auch an, die Sprünge zu reduzieren, also zB. sechzehn mal die Operation (für n ... n+15) hinzuschreiben in der Hoffnung, dass sich durch pipelining noch etwas rausholen lässt. Auf die Schnelle konnte ich das jetzt nicht testen :/

Ach und noch etwas: dieses ständige
fstp
wait
ist der blanke Unfug. Ich würde alle Werte im Stack halten, wozu immer speichern und laden?

Man muss übrigens nicht ständig prüfen, man kann auch Testen, wann das oft besungene Kind in den Brunnen gefallen ist und dann die letzten Glieder wieder wegsubtrahieren. Eine Vorwärtsberechnung im 16er-Pack sieht dann so aus:

Delphi-Quellcode:
// init
fld [Ergebnisvariable] //  0
fld [const_1]         //  const = 1
fld [const_1]         //  n

// Schleifenanfang

fld st(1)             // st(0) = 1
fdiv st(0), st(1)     // st(0) = st(0) / n
faddp st(3), st(0)    // ergebnis = ergebnis + st(0), pop st(0)
fadd st(0) st(1)      // n = n + 1

fld st(1)             // st(0) = 1
fdiv st(0), st(1)     // st(0) = st(0) / n
faddp st(3), st(0)    // ergebnis = ergebnis + st(0), pop st(0)
fadd st(0) st(1)      // n = n + 1

fld st(1)             // st(0) = 1
fdiv st(0), st(1)     // st(0) = st(0) / n
faddp st(3), st(0)    // ergebnis = ergebnis + st(0), pop st(0)
fadd st(0) st(1)      // n = n + 1

fld st(1)             // st(0) = 1
fdiv st(0), st(1)     // st(0) = st(0) / n
faddp st(3), st(0)    // ergebnis = ergebnis + st(0), pop st(0)
fadd st(0) st(1)      // n = n + 1

// ... noch weitere 12x


// Abbruchtest und Schleifenende ...

// end
FCOMPP                 // pop st(0) + st(1)
fstp [Ergebnisvariable] // save, pop

// überschüssige Glieder wieder wegsubtrahieren

// ...

Man arbeitet da zwar nicht ganz nach den Vorstellungen einer Stackmaschine... aber wer hat gefragt, ob es der FPU gefällt :cheers: Die Idee, viele Befehle untereinander zu schreiben reduziert den Schleifenoverhead

Befehlsreferenz

Amateurprofi 6. Dez 2009 16:00

Re: Ein bisschen InlineAssembler hilfe :)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Der Threadersteller war mit dem Zeitbedarf des in #1 gezeigten Pascal-Codes unzufrieden, vermutete, daß ein Assembler-Code schneller sein könnte und bat um Hilfe bei der Umsetzung.
Einige der Kommentare animierten mich, dieses Thema aufzugreifen. Das Resultat findet ihr im Attachment.

Zitat:

Ich denke mal bei solch trivialen Operationen bringt es keinen Geschwindigkeitsvorteil, wenn man sie in Assembler umsetzt.
Zitat:

Das ließe sich zwar übersetzen, aber das würde wie schon gesagt eher keinen Geschwindigkeitsvorteil bringen.. eher das Gegenteil
Doch, gerade bei solch trivialen Operationen läßt sich durch einen guten Assembler-Code viel erreichen, es sei denn man sähe eine Verbesserung um 800-1000 % als "keinen Geschwindigkeitsvorteil" an.
Natürlich bringt es nicht viel, wenn man sich im Debug-Mode anschaut, was der Compiler aus dem Source-Code gemacht hat, dieses abtippt und dann als die optimierte Assembler-Version ansieht.

Zitat:

PS: wir hatten hier schon ein paar Mal, daß die hochoptimierten (Versuche von Menschen) ASM-Codes wesentlich langsamer oder wenigstens/zumindestens genauso schnell waren, wie die optimierten Delphi-Codes aus 'nem Pascal-Compiler.
Die waren dann aber nicht von mir.

Zitat:

600% + (Amd64 SSE3) müssten locker drin sein.
Und auch das ist noch pessimistisch.

Das anhängende Programm enthält 9 unterschiedliche Code-Versionen sowie die Möglichkeit diese bezüglich Performance zu testen. Ich glaube, daß die Oberfläche mehr oder weniger selbsterklärend ist, habe aber einen Hilfefile beigefügt, der mit der F1-Taste angezeigt wird. Es wird vorausgesetzt, daß SSE2 verfügbar ist.

Die Routinen:
1) "PAS_SC (SC=Single Core)
Das ist im Prinzip der vom Threadersteller vorgegebene Code. Diese Version ist nicht multicorefähig. Bei ihr kann nur der Zielwert vorgegeben werden und dieser muß integer sein.
2) "FPU_SC"
Das ist die Übersetzung in Assembler. Auch diese Routine ist nicht multicorefähig und auch hier kann nur der Zielwert vorgegeben werden, der allerdings auch eine Fließkommazahl sein darf.
3) "MMX_SC"
Ebenfalls eine nicht multicorefähige Assembler-Routine, die aber mit den jeweils unteren Hälften der XMM-Register arbeitet.
4-6) "PAS_A", "FPU_A", "MMX_A"
Das sind multicorefähige Versionen. Bei der XMM-Routine wird die volle Breite der XMM-Register genutzt.
7-9) "PAS_B", "FPU_B", "XMM_B"
Hier wurde der Vorschlag aus #24 aufgegriffen, nicht nach jeder Rechnung zu prüfen, ob die Abbruchbedingung erfüllt ist sondern z.B. nur alle 16 Mal zu prüfen. Das Ergebnis ist eher ernüchternd, weil so gut wir keine Verbesserung zu verzeichnen ist.

Die nachstehende Tabelle zeigt ermittelte Rechenzeiten (CPU Intel Core 2 Duo E8400 3.0 GHz) für die verschiedenen Routinen. Es zeigt sich, daß Verbesserungen der Performance um den Faktor 8 bis 10 erreicht werden. Bei einer Quad-Core CPU dürften die Verbesserung deutlich höher sein.

Code:
Zielwert  20       20      25     25
Cores      1        2       1      2
Zeit in   ms      ms      s     s
-------- ----     ----     ---    ---
PAS_SC  4420     -        649      -
FPU_SC  2160     -        306      -
XMM_SC  2270     -        325      -
PAS_A   4160     2130     661    330
FPU_A   2060     1130     298    150
XMM_A   985       547     135     68
PAS_B   4200     2170     612    308
FPU_B   2080     1090     299    151
XMM_B   968       547     136     68

helgew 6. Dez 2009 18:00

Re: Ein bisschen InlineAssembler hilfe :)
 
Guten Abend Klaus,

vielen Dank für deine Mühe! Mein Vorschlag macht dann Sinn, wenn nur wenige Befehle pro Durchlauf ausgeführt werden müssen und der Übergang zwischen den Befehlen am Ende und am Anfang des Schleifenblocks ohne direkten Bezug auf die gleichen Register oder Speicherinhalte abläuft, zumindest sieht so meine Vorstellung von pipelining-Optimierung aus. Vielleicht kannst du mich ja diesbezüglich erleuchten :-)

Medium 6. Dez 2009 22:30

Re: Ein bisschen InlineAssembler hilfe :)
 
Wie parallelisierst du den Algorithmus? (Hab grad kein Delphi-Parser zur Hand, und das Riesenprogramm war ohne Highlighting bei der Formatierung praktisch undurchschaubar :snowball:)

Amateurprofi 7. Dez 2009 13:22

Re: Ein bisschen InlineAssembler hilfe :)
 
@helgew

Innerhalb der Schleife wird folgende Sequenz 16 Mal ausgeführt.
Es ist im Prinzip exakt die von dir vorgeschlagene Sequenz (die sich ja aus dem Problem fast zwingend ergibt)
War für mich auch überrraschend, daß das nichts bringt.

Code:
fld    st(2)    // st0=1
fdiv   st,st(1) // st0=1/Divisor
faddp  st(4),st // Summe=Summe+1/Divisor
fadd   st,st(2) // Divisor=Divisor+1
noch mal zum Vergleich die Sequenz aus deinem Vorschlag
Code:
fld    st(1)        // st(0) = 1 
fdiv   st(0), st(1) // st(0) = st(0) / n
faddp  st(3), st(0) // ergebnis = ergebnis + st(0), pop st(0)
fadd   st(0), st(1) // n = n + 1

R2009 7. Dez 2009 13:43

Re: Ein bisschen InlineAssembler hilfe :)
 
Hi,

Auf 1/n=0 abzuchecken ist mathematisch Quatsch!
Da dieser Fall niemals eintreten kann solltest du auf kleine Werte checken.
1/n < epsilon. Wobei epsilon beliebig klein werden kann.

es gilt:
lim 1/n = 0
n->unendlich

Grüsse
Rainer

Amateurprofi 7. Dez 2009 13:45

Re: Ein bisschen InlineAssembler hilfe :)
 
@Medium:

eigentlich ist das ganz simpel.
Aus dem Zielwert (Summe der Reihe) errechne ich die Anzahl der Elemente der Reihe, also die Anzahl der Durchläufe.
n = Trunc(Exp(Zielwert-0.57721566490153286))
Nehmen wir an ich will in zwei Threads rechnen, dann muß jeder Threat n div 2 Elemente addieren.
also:
h:=n div 2
Erster Threat rechnet 1/1 + 1/2 + ... + 1/h
Zweiter Thread rechnet 1/(h+1) + 1/(h+2) + ... + 1/n
Jeweils nach Ende eines Threads werden die Summen addiert.
Wenn alle Threads fertig sind, wird die Summe geprüft und es werden ggfs. noch Elemente addiert bzw. subtrahiert.

Medium 7. Dez 2009 14:02

Re: Ein bisschen InlineAssembler hilfe :)
 
Ah, n ist vorab bestimmbar, alles klar :) Danke!

Amateurprofi 7. Dez 2009 19:59

Re: Ein bisschen InlineAssembler hilfe :)
 
@Medium:
ja, aber es ginge auch ohne das.
Nimm an du willst auf 4 Threads verteilen.
Thread 1 rechnet 1/1 + 1/5 + 1/9 ...
Thread 2 rechnet 1/2 + 1/6 + 1/10 ...
Thread 3 rechnet 1/3 + 1/7 + 1/11 ...
Thread 4 rechnet 1/4 + 1/8 + 1/12 ...
Der erste Thread startet also mit dem Divisor 1 und die folgenden Threads starten mit einem um jeweils 1 höheren Divisor und alle Threads erhöhen den Divisor jeweils um n.
Abbruchbedingung aller Thraeds ist Summe>=Zielwert.
(Im Nachherein wundert es mich, warum ich das so umständlich gemacht habe.)

Medium 7. Dez 2009 23:04

Re: Ein bisschen InlineAssembler hilfe :)
 
Da hättest du das gleiche Problem, dass ich auch gedanklich hatte, als ich den Algo als nicht parallelisierbar bezeichnet hab: Abbruchbedingung ist die Summe aller Thread-Teilergebnisse, d.h. sie müssten nach jeden Schritt synchronisiert, die Summe gebildet und dann ggf. fortgeführt werden. Zwar "erschlägt" man so viele Divisionen wie man CPUs hat auf ein Mal, jedoch ist der organisatorische Aufwand hoch. Und auch dass alle Threads nach jedem Zyklus angehalten werden müssen, und die Summe ja nur noch ein-threadig berechnet wird ist der Sache auch wenig dienlich.
Und was macht man, wenn n jetzt kein Vielfaches der CPU-Anzahl ist? Dann schießt man ggf. über das Ziel hinaus, und muss das noch extra behandeln. Letztlich müsste man es aber wohl auf einen Versuch ankommen lassen um das brauchbar zu bewerten :).

Amateurprofi 9. Dez 2009 22:17

Re: Ein bisschen InlineAssembler hilfe :)
 
@Medium:
Oh, ja, da hast du Recht: Abbruchbedingung wäre für alle Threads die Gesamtsumme. Da bin ich wohl zu kurz gehopst, als ich sage es ginge auch ohne den Wert n zu kennen.
Jedoch ist es kein Problem, wenn n kein Vielfaches der CPU-Anzahl ist. Man kann ja (und genau das macht auch mein Programm) nachdem alle Threads fertig sind, noch fehlende Glieder dazu addieren bzw. welche subtrahieren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:33 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz