AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Unbegrenzt viele Nachkommastellen

Ein Thema von c113plpbr · begonnen am 8. Dez 2003 · letzter Beitrag vom 9. Aug 2011
Antwort Antwort
Seite 8 von 12   « Erste     678 910     Letzte »    
Benutzerbild von Dano
Dano

Registriert seit: 12. Aug 2004
49 Beiträge
 
#71

Re: Unbegrenzt viele Nachkommastellen

  Alt 17. Okt 2004, 20:32
hi Hagen

hab mal ein paar fragen
Delphi-Quellcode:
// division with remainder, Q = A div B & R = A rem B
procedure NDivRem(var Q,R: IInteger; const A,B: IInteger); overload;
// division with modular remainder, Q = A div B, R = A mod B
procedure NDivMod(var Q,R: IInteger; const A,B: IInteger); overload;
beides ist eine restberechnung
wo ist nun der genaue unterschied zwischen MOD und REM ?

Delphi-Quellcode:
// modular squaring, A = A^2 mod 2^k, A = B^2 mod 2^k
procedure NSqrMod2k(var A: IInteger; const B: IInteger; K: Cardinal); overload;
was ist MOD2K?
wie muß man sich das vorstellen?

ich hoffe du kannst ein bischen licht in mein dunkel mit dem ganzen "modularen" bringen^^
und was ist "montgomery domain" ???

mfg Dano
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#72

Re: Unbegrenzt viele Nachkommastellen

  Alt 18. Okt 2004, 06:06
Zitat:
wo ist nun der genaue unterschied zwischen MOD und REM ?
MOD und REM unterscheiden sich darin wie das Vorzeichen des Ergebnisses ausgerechnet wird. Während REM = Remainder = Rest sich exakt so verhält wie wir es in der Schule gelernt haben, sprich Vorzeichen des Restes ist das Vorzeichen des Dividenden, wird bei MOD = Modular = das Vorzeichen aus dem Divisor ermittelt. Somit wird MOD auch sehr häufig nicht als mathematische Operation einer Division gesehen sondern als Kongruenzklassen Operator. D.h. MOD stellt in modularen Ringen die Kongruenz einer Restklasse sicher.

Zitat:
// modular squaring, A = A^2 mod 2^k, A = B^2 mod 2^k
procedure NSqrMod2k(var A: IInteger; const B: IInteger; K: Cardinal); overload;

was ist MOD2K?
wie muß man sich das vorstellen?
Der Remark sagt schon alles:
-> A = A^2 mod 2^k

Vorstellen kannst du es dir so:
-> x = 1234^2 mod 2^16 == 1234^2 mod $10000;

Solche Operationen sind enorm schnelle Divisionen auf Binärrechnern, logisch da eine Division zu 2^k = ein Exponent zu Basis 2, eben nichts anders wie eine UND Verknüpfung mit 2^k -1 darstellen. Nach A^2 wird also das Resultat auf k Bits abgeschnitten, da man ja mit einer Binärzahl modular dividiert die aus k-1 ein Einsen besteht. Zb. A mod 2^1024 == A and (2^k-1) == A and 0b111111111.111111. Der Divisor besteht also als Binärzahl aus k-1 Einsen. Technisch gesehen bedeutet dies aber nur das man jeden Dividenden einfach auch k Bits in der Größe anbschneidet. Intern im DECMath wird zu jedem IInteger die Größe der verwendeten 32 Bit Werte verwaltet. D.h. die IInteger bestehen aus einem Linearen Speicherbereich der die Zahl enthält und einem Zähler wieviele Cardinal == 32Bit Werte man benötigt um diese große Zahl zu speichern. Eine MOD 2^k Operation wird also im Grunde immer nur diesen Zähler verkleinern und maximal den höchsten 32 Bit Wert im Speicher AND verknüpfen. Der Performancetechnisch Aufwand der MOD 2^k Operationen beschränkt sich demnach immer nur auf eine 32Bit breite AND Operation, auf bei Zahlen und einem k von vielen tausenden Bits.

Will man Zb. 1 Million Nachkommastellen von Pi berechnen, benötigt davon aber nur die letzten 8 Hexadezimalen Ziffern, dann kann man das so machen das nach jeder Operation mit MOD 2^32 -> k = 32, modular verkürzt. Du kannst dir nun vorstellen das es ein gewaltiger Unterschied in der Performance ist ob man nur mit 32 Bit großen Werten oder mit 125.000 Bit großen Zahlen rechnet.
Man berechnet also nur Teilziffern der gesuchten Zahl und kann so effizient und sehr schnell seine Ergebnisse mit zB. Testdaten aus dem Internet vergleichen. Man erhöht nun k, ausgehend von 32 so das nach jeder richtigen Teilberechnung die nächste Berechnung mit k * 2 durchführt. So kann man sehr effizient Überprüfungen durchführen.

In NCombi.pas findest du viele solcher Verfahren die intern modulare Divisionen mit 2^k durchführen können. Zb. möchtest du 2*3*5*7*13.....65537 mod 2^32 berechnen, also das Primorial = Produkt aller Primzahlen zwischen 0 bis 65538 modulo 2^32, also nur die letzten 32 Bits = 8 Hexadezimalen Ziffern. Du benutzt dazu NPrimorial(A, 0, 65538, NInt("HEX:100000000")); d.h. der Modulare Divisor ist 2^32. Intern ruft nun NPrimorial nach jedem Rechenschritt NMod(x, 2^32) auf, und NMod() wiederum kann überprüfen ob der Divisor eine echte Potenz von 2 ist, d.h. NMod() berechnet wenn möglich das k == 32. Falls das zutrifft wird nicht mehr mit einer langsammen Standarddivision gerechnet sondern eben einfach mit Beschneidung des Resultates auf k == 32 Bits.

Solche Feinheiten werden erst dann relevant wenn man Zb. bestehende Algorithmen in/aus anderen Libraries nach/von DECMath umsetzt, und sich dann bei Berechnungen mit mod 2^k Zahlen wundert warum DECmath um so vieles schneller als andere Libraries ist. Dies liegt eben daran das DECMath intern so weit dies effizient möglich ist bei vielen Operationen das schnellste Verfahren zur Lösung der Aufgabe ermittelt. Gerade die häufigsten Operationen wie die modulare Exponentation, modulare Multiplikation, modulare Quadrierung usw. profitieren dann davon wenn man mit mod 2^k berechnet.

Zitat:
was ist "montgomery domain" ???
Montgomery, war ein sehr trickreicher Mathematiker. Er hat einige wirklich interessante Algorithmen entdeckt die verschiedene mathematische Operationen, gerade im Langzahlbereich, sehr beschleunigen. Und da ist eben der Montgomery Trick zur Modularen Division hervorzuheben. Montgomery's Trick basiert im Grunde darauf das man alle Berechnungen zu einem ganz bestimmten Divisor in dessen Montgomery Darstellung durchführt. Dies vereinfacht und beschleunigt dann die Restebildung der nachfolgenden wiederholten modularen Montgomery Divisionen ernorm. D.h. mit Hilfe des Montgomery Tricks kann man zB. die Modulare Exponentation -> A = A^E mod M, beschleunigen. Allerdings darf M bestimmte Zahlenbereiche nicht überschreiten. In DECMath wird M < 2^8192 sein, damit intern dann Montgomerys Trick angewendet wird. Bei größeren Zahlen sind die in DECMath integrierten Divisionen wieder schneller als der Montgomery Trick.

Für eine genaue Beschreibung solltest du besser im Internet danach suchen. Interessant an den meisten Montgomery Tricks ist aber der Fakt das diese Tricks zu einer Zeit entdeckt wurden als man mit Langzahlen wie sie heute durch Computer möglich gemacht werden, damals noch garnicht gab. D.h. Montgomery hat viele Tricks gefunden die zu seiner Zeit keinerlei reale Bedeutungen hatten. Erst viel viel später besann man sich auf diese schon bekannten Tricks zurück um damit verschiedenen Computerberechnungen zu beschleunigen. Fazit: Montgomery hat Wissen entdeckt nur weil es entdeckbar war, und nicht weil man es zur Lösung eines konkreten Zieles nötig war
Oder anders ausgedrückt: man entdeckt irgendwas und erfindet erst danach eine konkrete Anwendung dafür.

Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#73

Re: Unbegrenzt viele Nachkommastellen

  Alt 18. Okt 2004, 06:40
Zu den Montgomery Funktionen zählen NMont(), NRedc() und NPowMod(). Die Montgomery Domain wird normalerweise in NPowMod() automatisch ausgewählt falls das zu einem Geschwindigkeitsvorteil auf dem jeweiligen Rechnertyp führt. D.h. in den meisten Fällen ist die interne Anwendung des Montgomery TRicks für dich als Anwender vollständig transparent, du bekommst davon nichts weiter mit. Es gibt aber sehr häufig die Notwendigkeit noch mehr spezielle Algorithmen mit DECMath zu entwickeln, die eben sehr viele modulare Divisionen zum gleichen Divisor durchführen. Da aber beim Montgomery Trick die Umwandlung der Zahlen in und aus der Montgomerydomain sehr rechenaufwändig sind, ist es vorteilhafter vor und nach solchen Spezialberchnungen nur einmalig diese Konvertierungen durchzuführen. Nun, dazu wurden eben die Funktionen NMont() und NRedc() verfügbar gemacht. Eine Anwendung dieses Falles sind die Funktionen zur Berechnng in Elliptischen Kurven in der Unit NGFps.pas.

Ich hätte diese Funktionen auch nur intern verwenden und deklarieren können, aber warum solche Funktionalität verstecken wenn man sie später eventuell gebrauchen kann ?

Fazit: diese Funktionen sind sehr sehr spezieller Natur, können aber wenn man weis wie und wo die Laufzeit ganz bestimmter Algorithmen stark positiv beeinflussen. Sie sind also nur Support-Funktionen.

Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#74

Re: Unbegrenzt viele Nachkommastellen

  Alt 18. Okt 2004, 22:51
Hi Dano,

ich habe mich mal des NRoot() Problemes angenommen. Du hast natürlich Recht gehabt, NRoot() berechnet unter bestimmten Umständen den Rest falsch.

Hier mal der korregierte Source für NRoot() aus meiner Lib.

Delphi-Quellcode:
function NRoot(var A,R: IInteger; const B: IInteger; E: Integer): Boolean;
// A = B^(1/E), R = B - B^(1/E)^E, returns R == 0 if B is a perfect power of E
// NRoot(1MBit, 3) = 31.6 seconds
// TBigNum.NRoot(1MBit, 3) = 44.9 seconds
// @A, @R can be nil, if both are nil we can check for PerfectPower
// todo: apply a recursive karatsuba newton method, equal to NSqrt()
resourcestring
  sNRoot = 'NRoot(), B must be > 0 and E > 0';
var
  X,Y,T: IInteger;
  I: Integer;
begin
  Result := True;
  if E <= 0 then NRaise(@sNRoot);
  I := NSgn(B, True);
  if I <= 0 then NRaise(@sNRoot);
  if (E = 1) or (I = 1) then
  begin
    if @A <> nil then NSet(A, B);
    if @R <> nil then NSet(R, 0);
  end else
    if E = 2 then
      Result := NSqrt(A, R, B)
    else
      begin
        NBit(Y, (NSize(B) + E -1) div E, True);
        Dec(E);
        repeat
          NSet(X, Y);
          NPow(T, Y, E);
          NMul(Y, T, E);
          NAdd(T, Y); // now here -> T = Y^E * (E +1)
          NMul(Y, X);
          NAdd(Y, B);
          NDivRem(Y, T, Y, T);
          I := NCmp(Y, X);
        until I >= 0;
 // HR, BugFIX!, we have to recompute on some circumstances the remainder
 // Thanks to Dano to pointing me out this.
        if I <> 0 then
        begin
          NPow(T, X, E +1);
          NSub(T, B, T);
        end;
        Result := NSgn(T) = 0;
        if @A <> nil then NSwp(A, X);
        if @R <> nil then NSwp(R, T);
      end;
end;
Gruß hagen
  Mit Zitat antworten Zitat
Benutzerbild von Dano
Dano

Registriert seit: 12. Aug 2004
49 Beiträge
 
#75

Re: Unbegrenzt viele Nachkommastellen

  Alt 20. Okt 2004, 00:18
hi Hagen

erstmal danke für deine sehr ausführliche erklärung von Mod/Mod2k/Montgomery
ich werde mir noch ein paar quellen im internet suchen um das zu vertiefen, aber im großen und ganzen habe ich das erstmal verstanden

dann danke für den bugfix von NRoot.... nun muß ich mir nur was einfallen lassen wie ich das am besten einbaue... wenn ich es in eine extra unit stecke und die dann bei uses importiere, nimmt er doch immer wieder die alte NRoot aus NInts.dcu


ich habe mich jetzt ein wehnig mit Interfaces beschäftigt... die sind eigentlich eine feine sache durch das referenzcounting. nur bei IInteger komme ich auf keinen grünen zweig. normalerweise müßte das interface mit einer klasse verbunden sein, aber so richtig fündig bin ich nicht geworden.
oder kann man interfaces auch ohne klasse verwenden?
da sie aber nur methoden haben dürfen kann ich mir das nicht vorstellen
was mich nun verzweifeln läßt ist das ich als variable nur ein interface deklariere und keine klasse oder struct. also wie verwaltet das interface dann seine daten wenn es keine felder hat?

leider sind die deutschen quellen im internet nicht sehr ergibig wie das interface intern so richtig arbeitet
muß ich doch mal auf dem englichen sector suchen

mfg Dano
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#76

Re: Unbegrenzt viele Nachkommastellen

  Alt 20. Okt 2004, 09:27
Hi Dano,

das sind sehr gute Fragen. Es ist richtig das IInteger KEINE Objecte sind aber denoch Interfaces. Es sind preallozierte Records bzw. genauer gesagt stinknormale Interfaces Der Irrglaube heutzutage ist eben das Interfaces aus Objecten bestehen müssen, falsch: die Objecte sind eine "umständlicher" Überbau auf die Interfaces. D.h. die einfachste Interface Implementierung sind Records.
Bisher kenne ich aber immer noch keine andere Delphi Source die dieses Tricks,wie bei IInteger, benutzen oder kennen.
Es gibt nun mehrere Gründe warum IInteger so arbeitet:

1.) das Interface von DECMath ist komplett prozedural -> sprich es macht keinerlei Sinn die IInteger als Objecte zu bauen, das procedurale Interface mit overloaded Fuctions ist wesentlich effizienter und ausbaubarer.
2.) der nötige Programcode-"Überbau" damit IInterface mit TObject funktioniert reduziert die Performance bei sehr häufigen Aufrufen der Interfaces, ohne dabei Vorteile zu bringen (siehe 1.) Nutzt man Records hat man das alles selber unter Kontrolle und kann es hoch optimieren.
3.) die Speicherbereiche der Interfaces als Records sind "prealloziert". D.h. es ist nun ein leichtes über einen eigenen "Memory Manager" -> NMath.NPool -> die Speicherbereiche von freigegbenen Interfaces zwischenzuspeichern und später wiederzuverwenden. D.h. indirekt stellen die Interfacemethoden von IInteger, im speziellen die Allokatorfunktion und die Methode ._Release; die Schnittstelle zum internen Speichermanager NPool dar. Denn exakt zum autom. Aufruf von ._Release + ._RefCount = 0 wird der Interface Record als freier Record im Pool des DEC Speichermanagers eingeordnet.
Das hat zB. zur Folge das bei der Berechnung von Pi zu 1 Million Dezimalstellen normalerweise ca. 250.000 mal ein Speicherbereich als Record-Interface vom Borland Speichermanager erzeugt werden müsste. Der Speicherpool NPool reduziert aber diese 250.000 Aufrufe auf ca. 1.000 tatsächlich Speicheranforderungen an den Borland MM. Im Falle Elliptischer Curven Berechnungen habe ich dabei eine Performancsteigerungvon ca. 10% erreicht. D.h. die IInteger Interfacemethoden stellen die Grndlage dafür dar, das man deren Speicherbereiche durch einen eigenen und optimierteren Speichermanager verwalten kann.
4.) das der Speichermanager im DECMath nun fast unabhängig vom Borland MM ist kann dieser auch speziell für Multi-Threaded Berechnungen optimiert werden. -> heist: NPool arbeitet Thread bezogen, jeder Thread installiert seinen eigenen NPool -> ergo bei IInteger-Allokationen verschiedener Thread kommen diese sich nur minimal in die Quere -> ergo kein Locking per RTLCriticalSection's wird benötigt -> ergo viel mehr Performance
5.) da der NPool als stark frequentierte Schnittstelle arbeitet, kann er dazu benutzt werden um ein Polling auf GUI Ebene durchzuführen. D.h. NPool ist auch verantwortlich das Computations-Management zu steuern, sprich über Benutzerinstallierbare Callback Interfaces kann der Programmierer periodisch Application.ProcessMesages aufrufen, oder in der Callback übder Abort eine Berechnung abbrechen, oder den zeitlichen- berchnungsmäßigen Fortschritt anzeigen. Für all diese Operationen muß der Programmierer aber NICHT in seinem mathematischem Code rumwurschteln. Man kennt das ja: man baut komplizierte Funktionen und muß darin das GUI mit Progressbars, Buttonabfragen usw. einbauen. Man muß also zeri komplette getrennte Sachen vermischen und verliert den Überblick. Nun, NPool implementiert also ein asynchrones, intervall-zeitgesteuertes Polling während der mathematischen Berechnungen.
6.) da nur die internen Funktionen im DECMath einen IInteger allozieren können, spricht man auch von Auto-allokatoren. D.h. du als Benutzer kümmerst dich NIE um die Allozierung, Zuweisung, Kopierung bei Veränderungen von IInteger Interfaces. Somit snd IInteger wie zB. LongStrings der RTL, Datenspeicher mit Autoallokation, Garbage Collections und Copy on Write Demand Feature.
Du kannst als zB. auch

Delphi-Quellcode:
var
  A,B,C: IInteger;
begin
// 1.) <- A,B,C werden automatisch mit NIL initialisiert

  NSet(A, 1);
// 2.) <- A wurde intern automatisch alloziert und mit 1 gefüllt

  B := A;
  C := B;
// 3.) <- Zuweisung von Variablen bedeutet das A,B,C auf das gleiche Object zeigen, wie bei Strings

  NInc(B);
// 4.) <- Veränderungen an B im Inhalt führen zum "Copy on Write Demand" Feature,
// B bekommt ein neue Interfacekopie alloziert, mit Inhalt '1'

  C := B;
// 5.) <- Interface A,C wird im refCounting um 1 dekremetiert,
// und C zeigt auf B, B Interface +1 im RefCounter

// 6.) <- über unsichtbare try finally Blöcke sind ALLE Interface Variablen im Delphi geschützt.
// hier also try finally, mit _Release(InterfaceArray[0..2]->@A)
// der Compiler legt also die Variablen A,B,C so im Speicher ab das sie in einem Array[0..2] of IInteger liegen
// somit kann er schnellere, Looporientierte Funktionen zum Freigeben dieser Interfaces benutzen.
end;
Schaue mal hier in die Code Library rein, da müsste es einen weitergehenden Beitrag zu meinem Interface-Trick -> "forged Interface" zu finden sein.

Gruß Hagen

PS: ein IInteger wie A := nil wird mathematisch als 0 betrachtet, so gesehen gibt es KEINEN logischen Zusammenhang zwischen einen allozierten IInteger Interface und einem NIL Interface. Mathematisch sind BEIDES Zahlen, die eine <> 0 die andere == 0. Dies vereinfacht die Denkweise wie man IInteger benutzen kann, sie sind fast ordinale Datentypen wie Integer, Comp, Real, Double etc. Am besten vergleichbar mit LongStrings.
Historisch gesehen sind IInteger die 3. Generation, nach zwei versuchen mit Objecten die wesentlich unhandlicher waren.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#77

Re: Unbegrenzt viele Nachkommastellen

  Alt 20. Okt 2004, 09:52
Hier mal die Linkszu weitergehenden Erklärungen:

http://www.delphipraxis.net/internal...ct.php?t=14605
http://www.delphipraxis.net/internal...ect.php?t=7357

Gruß hagen
  Mit Zitat antworten Zitat
Benutzerbild von Dano
Dano

Registriert seit: 12. Aug 2004
49 Beiträge
 
#78

Re: Unbegrenzt viele Nachkommastellen

  Alt 21. Okt 2004, 03:49
Hi Hagen

die beiden links sind gold wert
nach ein paar gemütlichen stunden mit dem debugger (*ironie*^^) habe ich erstmal die ganze genialität der sache regestriert^^
alles habe ich noch nicht raus....aber kommt noch

ich versuch es mal zusammenzufassen:
(ich hoffe du korrigierst mich falls ich irgendwas falsch interpretiere^^)

im grunde nutzen wir nur ein verhalten vom compiler das er bei Interfaces zeigt....
Interfaces wie sie hier benutzt werden sind im prinziep nur zeiger auf eine VMT wobei uns der compiler ein haufen arbeit abnimmt....
im grunde kann man sie wie objekte/klassen verwenden....



1. locale interface variable
var MyIInteger: IInteger hier wird MyIInteger auf dem stack angelegt und mit nil initialisiert
das besondere hierbei ist das sie mit nil intialiesiert wird was bei anderen localen var (z.B. Pointer, Integer) nicht der fall wäre, die haben irgendwelche werte die vorher auf dem stack lagen....
(das so erzeugte MyIInteger würde ich mir in gewisser weise als Pointer vorstellen)


2. funktions/procedur - aufrufe die so ein Interface als parameter haben
NSet(MyIInteger,1); die funktionen testet ob MyIInteger nil ist
if @MyIInteger <> nil then...... wenn sie nil ist dann wird eine funktion aufgerufen die dem interface eine VMT zuweist und speicher reserviert.... dazu komme ich gleich noch
wenn sie nicht nil ist hat sie eine VMT und ist damit bereits initialisiert und kann verwendet werden....


3. zuweisungen
MyIInteger1:= MyIInteger2 hier ruft der compiler automatisch IntfCopy auf
procedure _IntfCopy(var Dest: IInterface; const Source: IInterface); dadurch wird bei Dest der refcounter um 1 erhöht und MyIInteger1 auf die VMT von MyIInteger2 geändert
und bei MyIInteger1 wird der refcounter um 1 verringert... fals er 0 wird, wird die VMT und der speicher von MyIInteger1 frei gegeben
beide interface zeigen jetzt auf die selbe VMT.....
dabei wird kein neuer speicher reserviert... halt wie bei Pointern


4. wenn der gültigkeitsbereich endet
also wenn das ende der funktion erreicht ist wird vom compiler automatisch IntfClear aufgerufen
function _IntfClear(var Dest: IInterface): Pointer; dabei wird der refcounter von MyIInteger um eins verringert
wird er 0, wird die VMT und der speicher von MyIInteger frei gegeben
auch bei MyIInteger:= nil; wird der refcount um 1 für die variable verringert



5. die VMT (Virtual Methode Tabel)
jedes interface hat eine VMT
Delphi-Quellcode:
type
  IInterface = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;
diese 3 methoden müßen von klassen die ein interface nutzen implementiert werden, das macht man am einfachsten in dem man TInterfacedObject als vorfahre der klasse mit einbindet

da unser interface MyIInteger in keine klasse eingebunden ist funktioniert das so nicht
deshalb müßen wir unsere VMT mit den 3 funktionen selber machen

jede funktion die als übergabeparameter eines unserer interfaces hat, prüft ob das interface auf nil zeigt
ist das der fall reservieren wir speicher für ein pointerarray das min. 3 einträge hat
die 3 pointer müßen wir natürlich auf funktionen zeigen lassen die wir selber noch implementieren müssen... die im prinzip das machen was die standartfunktionen eines interfaces machen
außerdem können wir hier auch noch unsere eigenen methoden mit einbauen... indem wir die VMT mit mehr einträgen machen (>3)
auch felder sind möglich, was bei normalen interfaces nicht möglich wäre



Fazit: der compiler übernimmt bei interfaces das was man bei normalen objecten mit create oder free selber machen müßte... man muß sich nicht um das aufräumen kümmern... speicherlecks sind eigentlich ausgeschlossen
allerdings muß man sich um die VMT selber kümmern... das ist zwar im ersten augenblick komplizierter, aber wenn es einmal gemacht ist kann man nie wieder das freigeben oder erstellen von objekten vergessen

in c++ ruft der compiler automatisch den construktor für ein objekt auf wenn es als lokale variable verwendet wird...ebenso den destruktor (natürlich kann man hier auch noch den zeiger auf ein objekt verlieren und ein speicherleck bekommen...)
schade das sowas nicht bei delphie automatisch geht... darum der umweg über die interfaces
aber großes plus bei interfaces ist das refcounting
und kein TObject *juhu*

den overhaed den TObjekt verursacht... *omg*
da haben meine klassen wehniger eigene funktionen und felder als das was sie von TObject aufgedrückt bekommen....
eigentlich auch schade das man klassen nicht ohne TObjekt erstellen kann
andererseits hat die VCL auch vorteile was besonders das RAD betrifft... interaktionen mit dem benutzer der anwendung werden doch extrem vereinfacht...


naja, ist bissel verworen was ich da geschrieben habe... aber ich denke mal das es halbwegs richtig ist^^
ich schnapp mir morgen erstmal das asm-buch.... hab mit tasm noch nix gemacht... nur masm... und da wird einiges anders sein bei pascal

lustig fand ich nur das ich die asm-funktion von waitcursor schneller kapiert habe als das delphie-construckt^^
kleiner schneller sauberer
naja... ich lerne ja erst noch den delphi-syntax

mfg Dano
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#79

Re: Unbegrenzt viele Nachkommastellen

  Alt 21. Okt 2004, 10:36
Hi Dano,

das war im Grunde alles korrekt, und ein Kompliment von mir weil dues ziemlich schnell erfasst hast.
Es gibt aber vielleicht noch einige kleinere Richtigstellungen:

1.) Delphi implementiert bei Interface Variablen ausschließlich das korrekte Initialisieren mit NIL und das korrekte Finalisieren mit NIL, mehr nicht. Diese beiden Aufgaben macht Delphi in geschützten Codeblöcken, also unsichtbaren try finally end; Blöcken.
Werden mehrere Interface-Variablen in einer Procedure benutzt so gruppiert der Compiler diese Variablen im Stack immer als Array[] of IInterface. Deren Initialisierung und Finalisierung mit NIL wird dann durch Funktionen der RTL erledigt die ganz Arrays of IInterface auf NIL setzen.
Das "auf NIL" setzen bedeutet das die RTL erstmal überprüft ob die Variable <> nil ist, wenn ja wird Valiable._Release; aufgerufen und Variable := nil; gesetzt.

2.) Interfaces können, müssen aber nicht das Reference Counting implementieren. Wenn sie es tuen dann nur aus dem Grunde um sich selber korrekt zerstören zu können. D.h. die Implementierung der Allokation + Deallokation der Interfaces wird nur durch die Interfaces erledigt.

Dies beiden Punkte stellen das "Garbarge Collection" Feature dar.

3.) Die proceduralen Schnittstellen im DECMath -> math. Funktionen, rufen intern bei nicht-readonly Variablen immer eine Funkton auf. Diese Funktion hat drei Aufgaben, a.) Überprüfung ob Variable ein nil Interface enthält und falls ja ein neues IInteger Intrface allozieren, und wenn nein b.) Variable enthält ein Interface also Überprüfung ob .RefCount > 1 ist, wenn ja neues IInteger Interface allozieren und Inhalt aus dem alten ind das neue kopieren. Der Kopierschritt wird aber durch einen Parameter gesteuert. c.) am Schluß gibt die Funktion einen Zeiger auf einen Record zurück -> sozusagen wndelt sie den Datentyp Pointer(IInteger) in PIIntegerRecord(IInteger) um.

Diese Funktion stellt also das "Copy on Write Demand" und "Autoallokation" Feature zur Verfügung.
In den meisten Fällen sieht das so aus:

Delphi-Quellcode:
procedure NInc(var A: IInteger; B: Integer);
begin
  with NAllocCopy(A)^ do
 .....
end;
NAllocCopy() ruft intern NAlloc(A, True) auf, und diese Funktion führt obigen Punkt 3. aus.
Durch die Deklaration mit "var A: IInteger" haben wir ja eine "by Reference" Aufrufkonvention, wir bekommen den Zeiger auf die Zeigervariable in der das IInteger steht, und somit können wir diesen Variablen neue IInteger Interfaces zuweisen. Es dürfte aber klar sein das solche Funktionen möglichst hochoptimiert sind. Im Falle von NAlloc() wird intern in den meisten Fällen nur 3 Assembler Instruktionen ausgeführt. Leider kennt Delphi keinen Precompiler und somit keine Makros.
Man sollte also wenn man mit Interfaces arbeitet immer die Aufrufkonventionen "var" oder "const" benutzen, dies ist wichtig.

4.) Interfaces sind keine Zeiger auf VMT's !! Sie sind Zeiger auf einen Speicherbereich in dem die ersten 4 Bytes == Pointer ein Zeiger gespeichert wurde der der Zeiger auf eine VMT ist. Nach diesem Pointer kommen noch eventuell Daten, die verschiedenen Felder/Member des allozierten Interface Objectes. Im Falle von IInteger also ein Zeiger auf ein Array[]of Cardinal, eine Count, Size Variable und Negative um das Vorzeichen zu speichern.
IInteger Interface Variablen könnte man also direkt zu einem Record casten und somit auf die internen Daten zugreifen. Man sollte das aber nicht machen

So, und alle diese Features waren noch vor dem ersten eingetippten Source ein zu erreichendes Ziel, d.h. ich habe mich nur deshalb für Interfaces und prozeduraler Schnittstelle entschieden da das die einzigste Möglichkeit im Delphi seinerzeit war.

Gruß hagen
  Mit Zitat antworten Zitat
Benutzerbild von Dano
Dano

Registriert seit: 12. Aug 2004
49 Beiträge
 
#80

Re: Unbegrenzt viele Nachkommastellen

  Alt 22. Okt 2004, 23:17
hi Hagen

ich habe mal ne kleines test-interface zusammengebastelt
ich deklariere ein interface
initialisiere mit einer function meine felder und die VMT
soweit läuft alles prima *juhu*

nun bereiten mir aber aufrufe denen ich einen parameter übergebe probleme

Delphi-Quellcode:
type
  IMyInterface = Interface(IInterface)
    function GetName: String; stdcall;
    procedure SetName(Name: String); stdcall;
    function GetRefCount: Integer; stdcall;
    property Name: String read GetName write SetName;
  end;
wenn ich TestInterface.Name:='Hallo! ;)'; aufrufe pusht er zuerst den zeiger auf den string
dann pusht er den zeiger auf meinen interface record
dann call't er die funktion SetName(Name: String)

soweit alles ok *freu*

jetzt kommt der übliche stackrahmen (push ebp, mov ebp,esp......) und dann will er den referenzzähler des string erhöhen, und das geht schief
der holt sie den falschen zeiger vom stack ( -> exception).... generell verwechselt er die var's aufm stack
die sind alle um eins verschoben..... ich denke mal das das interface automatisch ein self aufn stack haut(macht er ja auch), und vom compiler wird das in der function nicht berücksichtigt

gibts für das problem ne lösung?

mfg Dano
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 8 von 12   « Erste     678 910     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:45 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