![]() |
Trunc / Frac -> Wie funktionieren die intern?
Hat jemand den Source der beiden Funktionen?
Hab leider keine Ahnung, wie die beiden intern funktionieren könnten. Ich dachte erst bei TRUNC:
Delphi-Quellcode:
und FRAC:
Result := Zahl div 1 //DIV funktioniert aber NUR bei Ganzzahl
Delphi-Quellcode:
Kann mir das jemand sagen?
Result := Zahl - Trunc(Zahl);
Danke |
Re: Trunc / Frac -> Wie funktionieren die intern?
Trunc, Frac und auch Round sind allesamt in Assembler programmiert. Sie benutzen also den speziellen Befehlssatz des Prozessors für Gleitkommazahlen und sind nicht durch Delphianweisungen realisiert.
|
Re: Trunc / Frac -> Wie funktionieren die intern?
Genau, die übergeben den Wert an die FPU, sagen dieser den zu verwendenten Rundungsmodus und lesen den Wert wieder aus.
Allerdings ist Trunc tatsächlich ein klein wenig umständlicher geschrieben (was aber wohl nicht ganz stören sollte) Wenn du es aber mal ganz genau wissen willst, dann schau entweder in die Quelltexte rein, oder mach dir'n Demoprogramm uns schau dir dort an was als ASM-Code wirklich ausgeführt wird. |
Re: Trunc / Frac -> Wie funktionieren die intern?
Einfach mal als Beispiel an Trunc:
Delphi-Quellcode:
...:cat:...
{ *********************************************************************** }
{ } { Delphi / Kylix Cross-Platform Runtime Library } { System Unit } { } { Copyright (c) 1988-2004 Borland Software Corporation } { } { Copyright and license exceptions noted in source } { } { *********************************************************************** } procedure _TRUNC; asm { -> FST(0) Extended argument } { <- EDX:EAX Result } SUB ESP,12 FNSTCW [ESP].Word // save FNSTCW [ESP+2].Word // scratch FWAIT OR [ESP+2].Word, $0F00 // trunc toward zero, full precision FLDCW [ESP+2].Word FISTP qword ptr [ESP+4] FWAIT FLDCW [ESP].Word POP ECX POP EAX POP EDX end; |
Re: Trunc / Frac -> Wie funktionieren die intern?
Danke für die Antworten.
Den Code hab ich auch schon mal gesehen. Da ich aber kein Assembler kann, weis ich absolut nicht, was der macht, vor allem das FWAIT. Und warum POP't man die Register ECX, EAX, EDX am Ende, wenn man doch gar nicht's gePUSH't hat? Auch warum man am Anfang 12 Bytes vorrutscht, versteh ich nicht. Und bei den Funktionen FNSTCW und FLDCW hört's ganz auf. Wäre schön, wenn sich jemand finden würde, der den Code erklären kann. |
Re: Trunc / Frac -> Wie funktionieren die intern?
Zitat:
Heutzutage ist die FPU in der CPU integriert. Wenn ich micht nicht irre braucht man deshalb solche FWAITs nicht mehr wirklich. Aber Borland will den Code wohl kompatibel zu älteren Prozessoren halten. Außerdem sorgt FWAIT noch dafür, dass anliegende FPU Exceptions sofort behandelt werden und das ist auch auf modernen Prozessoren noch relevant. Denn wenn eine FPU Exception auftritt, wie z.B. eine Division durch Null, dann passiert erst mal gar nichts. Das Programm könnte munter weiterlaufen, bis zum nächsten FPU Befehl, der auf anliegende Exceptions prüft. Zitat:
Der erste Befehl reserviert 12 Bytes auf dem Stack, quasi lokale Variablen. Nämlich 2 Bytes, um das aktuelle FPU Control Word zu sichern (save) und später zu restaurieren, 2 Bytes zum Basteln des neuen Control Words (scratch) und schließlich 8 Bytes für das Ergebnis. Zitat:
FLDCW = LoaD Control Word. Das Control Word ist ein 16-Bit-Wort, das gewisse Einstellungen der FPU enthält, unter anderem wie gerundert wird und mit welcher Präzision gearbeitet wird. Zitat:
Falls nicht, hier alles nochmal zusammenhängend:
Delphi-Quellcode:
procedure _TRUNC;
asm // Eingabe: Extended-Wert, der gerundet werden soll, in FST(0) // Ausgabe: Int64-Wert in EDX:EAX // Platz für lokale/temporäre Variablen auf dem Stack reservieren SUB ESP,12 // FPU Control Word auf reservierten Stackplatz sichern FNSTCW [ESP].Word // save // und noch eine zweite Kopie sichern FNSTCW [ESP+2].Word // scratch // warten, bis FPU mit obigem Befehl fertig ist FWAIT // bestimmte Bits der 2. Stack-Kopie des Control Words auf 1 setzen, sodass FPU auf 0 // abrundet (also Nachkommastellen abschneidet) und mit voller Präzision rechnet OR [ESP+2].Word, $0F00 // trunc toward zero, full precision // modifizierte Stack-Kopie des Control Words in FPU laden und somit aktivieren FLDCW [ESP+2].Word // jetzt kommt die eigentliche Arbeit ;) // Gleitkommawert, der sich gerade in ST(0) befindet (also unser Parameter) als // Integer auf den Stack nach [ESP+4] speichern und dabei gemäß des aktuellen // Control Words runden (truncate!) // Außerdem wird der FPU-Registerstack "gePOPpt", aber das tut hier nichts zur Sache FISTP qword ptr [ESP+4] // wenn eine FPU Exception aufgetreten ist, dann jetzt sofort behandeln // Es könnte ja versucht worden sein, einen Wert zu runden, der so groß (oder so klein) // ist, dass er nicht mehr als Int64 dargestellt werden kann. Wenn das der Fall war, // wollen wir an dieser Stelle informiert werden und nicht erst unabsehbar später. FWAIT // ursprüngliches FPU Control Word wieder restaurieren (zurück in die FPU laden) FLDCW [ESP].Word // ursprüngliches und modifiziertes Control Word vom Stack entfernen // die Werte sind jetzt unwichtig, man könnte genausogut ADD ESP,4 schreiben, aber // der Befehl POP ECX ist kleiner und ECX darf gefahrlos verändert werden POP ECX // gerundetes Ergebnis vom Stack entfernen und in die Register EDX:EAX laden POP EAX POP EDX end; |
Re: Trunc / Frac -> Wie funktionieren die intern?
Ich danke dir.
Schön, dass du dir die Zeit genommen hast, mir das ganze so umfangreich zu erklären :thumb: :dp: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:15 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz