![]() |
Exponent aus Extended extrahieren?
weiß jemand, wie man am schnellsten den Exponent aus einem Extended extrahieren kann?
(am besten als Dezimalzahl) |
Re: Exponent aus Extended extrahieren?
Logarithmus? ;-)
|
Re: Exponent aus Extended extrahieren?
bei "schnell" dachte ich eher an Assembler und SHL Befehle und so :-) ..
ich hab hier auch schon was gefunden. ![]() warum muss man erst den Exponent erst mit
Delphi-Quellcode:
prüfen?
if ExtRec(B).Exp and $7FFF = $7FFF then
und warum steht da noch?
Delphi-Quellcode:
(ExtRec(B).Exp and $7FFF) - $3FFE - 64;
|
Re: Exponent aus Extended extrahieren?
schau da mal in der FMath.pas die Functionen FloatConvert an.
![]()
Code:
- Vorzeichen
Single 8/23
-eEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM Double 11/52 -eEEEEEE EEEEMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM Extended 15+1/63 -eEEEEEE EEEEEEEE SMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM E Exponent M Mantisse je Gruppen á 8 Bit / 1 Byte |
Re: Exponent aus Extended extrahieren?
@stoxx:
Zur Frage : warum muss man erst den Exponent erst mit
Delphi-Quellcode:
prüfen
if ExtRec(B).Exp and $7FFF = $7FFF then
Weil, wenn der Exp = $7FFF ist, die Zahl eine NaN (Not a Number) oder Infinite (Unendlich) ist. Weiter sollte man prüfen, ob beide, Mantisse und Exponent, = 0 sind. Dann ist die Zahl = 0. |
Re: Exponent aus Extended extrahieren?
Hi Himitsu,
Du, ich hab mir gerade mal Deine Unit FMath angschaut. Die ganzen Bitmasken, die Du da gleich vordefinierst, sehen sehr effizent aus. BitInt Erfahrung hast Du auch noch. Vielleicht hast Du ja einen guten Tip? wir haben einen Fixcomma64 Datentyp. Dieser hat hat feste 9 Nachkommastellen. Intern wird es als int64 Wert gespeichert. wenn man die Zahl z.b. als Double haben möchte, muss man durch den Skalierungsfaktor teilen. die gespeicherte Zahl ist quasi also immer um 10^9 zu groß ...
Delphi-Quellcode:
Leider ist die Multiplikation um Faktor 10 langsamer als eine reine Double Multiplikation.
// Double
class operator FIXCOMMA64.Implicit(const AValue: FIXCOMMA64) : double; begin Result := AValue.FBCD9 / FBCD9EXT; end; Am besten wäre, wir hätten eine MulDiv64 Funktion, aber die hatte ja leider damals nicht funktioniert. Du hattest Dich auch mal dran versucht, diesen C Quelltext zu übersetzen, weiß nicht, ob Du Dich noch erinnerst. Die Funktion ist sicher nun viel zu umständlich. Erst wird das Ergebnis in extended ausgerechnet. Danach der vorkomma und Nachkomma Anteil getrennt behandelt. Der Nachkommaanteil wird dann noch gerundet. Das erfolgt so, in dem mit einem Faktor multipliziert, der um Faktor 10 zu groß als Skalierungsfaktor selbst, danach wird gerundet und wieder durch 10 dividiert. das alles dient dazu, um keine Ungenauigkeiten reinzubekommen, wie bei Gleitkommazahlen üblich. funktioniert auch alles soweit. nur eben seeehr langsam ... iDiv64 ist aus dem Fastcode projekt .. jetzt war meine Idee .. man würde jetzt den Exponenten auslesen. Mit einem Faktor a multiplizieren, um zu runden und durch 10 zu dividieren. der Faktor a müsste nun die Differenz zwischen dem neuen ermitteltem Exponenten und dem Zielexponenten von 10^-9 sein, damit die Zahl als BCD Wert reingeschrieben werden kann. Fällt Dir vielleicht etwas intelligenteres ein? Vielleicht kannst Du ja mal drüber gucken ! danke Dir schonmal !
Delphi-Quellcode:
//====[ * ]===================================================================
class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64; var val: extended; begin // FBCD9INT = 1000000000; // FBCD9EXT = 1000000000.0; // FBCD10INT = 10000000000; // FBCD10EXT = 10000000000.0; val := (Left.FBCD9 / FBCD9EXT) * (Right.FBCD9 / FBCD9EXT); Result.FBCD9 := (Trunc(val)*FBCD9INT) + iDIV64(Round(frac(val)*FBCD10EXT), 10); end; |
Re: Exponent aus Extended extrahieren?
Du weißt aber, daß du so über 'nen Extended gehst/rechnest und damit unter Umständen die letze (9.) Kommastelle einbüßt.
In welchem Bereich liegen denn deine Werte? Wenn die im Bereich -9,223372036854775808 .. 9,223372036854775807 liegen, dann könnte man einfach:
Delphi-Quellcode:
.FBCD9 ist och ein Int64?
class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64;
var val: extended; begin Result.FBCD9 := (Left.FBCD9 * Right.FBCD9 + (FBCD9INT div 2)) div FBCD9INT; end; Bei größerem Wertebereich müßte am den Überlauf abfangen, also sozusagen die Multiplikation mit 128 Bit-Integern berechnen, bzw. die Berechnung auf 2 64-Bit oder besser noch auf 4 (vier) 3 32-Bit-Integer (für 32-Bit-CPUs) zerlegen. praktisch so, wie es Delphi schon beim Int64 macht ... nur größer |
Re: Exponent aus Extended extrahieren?
Zitat:
Zitat:
die Werte haben folgenden Wertebereich
Delphi-Quellcode:
FBCD9Min = int64($8000000000000001); // -9223372036.854775807
FBCD9Max = int64($7FFFFFFFffffffff); // 9223372036.854775807 Zitat:
|
Re: Exponent aus Extended extrahieren?
ich wollte es jetzt mit der Integeraritmetik der FPU probieren, so wie es Currency auch macht, damit scheint es zu funkionieren.
Ich bekomme aber die Variablen bei den Class operatoren nicht in die FPU. Da steht immer Müll im st(0) und st(1). Weißt Du, wie es geht?
Delphi-Quellcode:
class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64;
asm Fild qword ptr [left.FBCD9] Fild qword [right.FBCD9] |
Re: Exponent aus Extended extrahieren?
ich glaub ich hab erstmal 'ne Lösung für den Bereich von etwas -96038,388 bis 96038,388 reicht aber aus, da die Multiplication bei rund 9223372036 = 96038*96038 eh einen Überlauf bringt.
(also 'ne Zahl kann natürlich auch größer als 96038,388 sein, wenn der andere Operand entsprechend kleiner ist)
Code:
Result := (left * right) div 1000000000;
***überlauf*** Result := left * (right div 1000000000) + (left * (right mod 1000000000)) div 1000000000 ***********überlauf************ Result := left.FBCD9 * (right div 1000000000) + ((left mod 1000000000) * (right mod 1000000000)) div 1000000000 + (left div 1000000000) * (right mod 1000000000); [s]und mit Runden der 9. Kommastelle (glaub ich) Result := left.FBCD9 * (right div 1000000000) + ((left mod 1000000000) * (right mod 1000000000)) div 1000000000 + ((left + 500000000) div 1000000000) * (right mod 1000000000);[/s] [edit] blödsinn
Delphi-Quellcode:
und das Andere :gruebel:
class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64;
begin Result.FBCD9 := left.FBCD9 * (right.FBCD9 div 1000000000) + ((left.FBCD9 mod 1000000000) * (right.FBCD9 mod 1000000000)) div 1000000000 + (left.FBCD9 div 1000000000) * (right.FBCD9 mod 1000000000); end;
Delphi-Quellcode:
[edit] das mit dem Runden wahr wohl blödsinn ... kommt davon, wenn man das Rechenergebnis mit einem Ergebnis via Floattypen vergleicht und denkt die eigene Rechnung stimme nicht ganz :nerd:
class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64;
const idiv: LongInt = 1000000000; asm fild qword ptr [&left.FBCD9] fild qword ptr [&right.FBCD9] fmulp st(1), st(0) fidiv dword ptr [&idiv] fistp qword ptr [&result.FBCD9] wait end; |
Re: Exponent aus Extended extrahieren?
ich habs jetzt so:
aber leider funktioniert: Fild qword ptr [&left.FBCD9] nicht. Da muss bei Class Operatoren irgendwas anderes übergeben werden. Auch dem Result kann man nix geben ..
Delphi-Quellcode:
//====[ * ]===================================================================
class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64; const I10 : LongInt = 10; BCD8INT : LongInt = 100000000; var // val: extended; f1, f2 : int64; begin // Result.MaxValue // val := (Left.FBCD9 / FBCD9EXT) * (Right.FBCD9 / FBCD9EXT); // // Result.FBCD9 := (Trunc(val)*FBCD9INT) + iDIV64(Round(frac(val)*FBCD10EXT), 10); // //exit; f1 := left.fbcd9; f2 := Right.fbcd9; asm // FILD I10 // FILD BCD8INT Fild qword ptr [f1] Fild qword ptr [f2] // Fild qword ptr [&left.FBCD9] // Fild qword ptr [&right.FBCD9] fmulp st(1),st(0) // FDIVR fidiv dword ptr [&BCD8INT] FRNDINT // FDIVR fidiv dword ptr [&I10] FISTP qword [f1] wait end; Result.FBCD9 := f1; end; so ist der definiert:
Delphi-Quellcode:
type PFIXCOMMA64 = ^FIXCOMMA64; FIXCOMMA64 = packed record
strict private FBCD9: int64; class function Get_MinValue: FIXCOMMA64; static; class function Get_MaxValue: FIXCOMMA64; static; private function Get_DWORD: DWORD; function Get_Int64: Int64; .... |
Re: Exponent aus Extended extrahieren?
also hier (D2009)ging das so, :gruebel:
wobei die direkte Integerversion doch eigentlich das Bessere sein sollte? da es sich von den Speicheradressen nix nimmt, sollte es auch so gehn und bei mir geht es auch. :angel2:
Delphi-Quellcode:
uses Math;
type PFIXCOMMA64 = ^FIXCOMMA64; FIXCOMMA64 = packed record strict private FBCD9: int64; private public class operator implicit(const float: Extended): FIXCOMMA64; class operator implicit(const rect: FIXCOMMA64): Extended; class operator Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64; end; class operator FIXCOMMA64.implicit(const float: Extended): FIXCOMMA64; begin Result.FBCD9 := Round(float * 1000000000); end; class operator FIXCOMMA64.implicit(const rect: FIXCOMMA64): Extended; begin Result := rect.FBCD9 / 1000000000; end; class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64; const idiv: LongInt = 1000000000; asm fild qword ptr [&left] fild qword ptr [&right] fmulp st(1), st(0) fidiv dword ptr [&idiv] fistp qword ptr [&result] wait end; procedure TForm2.FormCreate(Sender: TObject); var f1, f2, f3: FIXCOMMA64; begin f1 := 1234.56789; f2 := 9876.54321; f3 := f1 * f2; if SameValue(f3, 12193263.111, 0.001) then Beep; end; |
Re: Exponent aus Extended extrahieren?
hm .. also in D2007 geht das so nicht, naja . .muss man halt die 3 Kopien verkraften :-(
aber nun zurück nochmal zu meiner Ausgangsfrage Ziel ist es eigentlich, von dem Fixcomma wegzukommen und Double umzustellen, der bei jeder Multiplikation gerundet wird. Damit man dann eben Gleitkommazahlen doch vergleichen kann. Dazu brauchte ich den Exponent .. Jetzt meine Frage bezieht sich der Exponent im Double oder Extended auf Binärsystem oder Dezimalsystem. also sagt die Zahl aus, wo das komma im Binärsystem verrutscht ist .. also da könnte ja die Zahl sehr groß seinn? Oder entspricht es der Exponentialdarstellung, im Dezimalsystem. Und wenn nein, wie kommt man dann auf 1.12323 E18 ohne nun mit FormatFloat erst den String rauszuholen um zu gucken? da bin ich etwas überfragt ... |
Re: Exponent aus Extended extrahieren?
und so?
Delphi-Quellcode:
class operator FIXCOMMA64.Multiply(const Left, Right: FIXCOMMA64): FIXCOMMA64;
const idiv: LongInt = 1000000000; asm mov eax, &Left fild qword ptr [eax] mov eax, &Right fild qword ptr [eax] fmulp st(1), st(0) fidiv dword ptr [&idiv] mov eax, &Result fistp qword ptr [eax] wait end; |
Re: Exponent aus Extended extrahieren?
Delphi-Quellcode:
asm
fild qword [eax] fild qword [edx] fmulp st(1),st(0) fidiv dword ptr [&BCD8INT] FRNDINT fidiv dword ptr [&I10] FISTP qword [ecx] wait end; Result entspricht dem ecx ? funktionieren tut es zumindest, aber liegt das result nicht immer auf eax? Ist das jetzt ein Problem da? liegt bei D2009 das ergebnis immer noch auf ecx? und darf man eax und edx nehmen? ich frage mich jetzt, ob eax immer 64 Bit groß ist? oder nur auf einem 64 Bit Prozessor? |
Re: Exponent aus Extended extrahieren?
in EAX ist hier nur der Pointer zu dem Record
EAX = 32 Bit AX = 16 Bit AL 8 Bit |
Re: Exponent aus Extended extrahieren?
Zitat:
EAX ist immer ein 32 Bit Register. Im 64 Bit-Mode gibt es 64 Bit Register (RAX, RBX, RCX, etc.) deren untere 32 Bits mit EAX, EBX, ECX, etc. angesprochen werden können. Hier zur Info aus Intels Basic Architecture eine Aufstellung der Register im 64 Bit Mode 3.7.2.1 Register Operands in 64-Bit Mode Register operands in 64-bit mode can be any of the following: • 64-bit general-purpose registers (RAX, RBX, RCX, RDX, RSI, RDI, RSP, RBP, or R8-R15) • 32-bit general-purpose registers (EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP, or R8D-R15D) • 16-bit general-purpose registers (AX, BX, CX, DX, SI, DI, SP, BP, or R8W-R15W) • 8-bit general-purpose registers: AL, BL, CL, DL, SIL, DIL, SPL, BPL, and R8LR15L are available using REX prefixes; AL, BL, CL, DL, AH, BH, CH, DH are available without using REX prefixes. • Segment registers (CS, DS, SS, ES, FS, and GS) • RFLAGS register • x87 FPU registers (ST0 through ST7, status word, control word, tag word, data operand pointer, and instruction pointer) • MMX registers (MM0 through MM7) • XMM registers (XMM0 through XMM15) and the MXCSR register • Control registers (CR0, CR2, CR3, CR4, and CR8) and system table pointer registers (GDTR, LDTR, IDTR, and task register) • Debug registers (DR0, DR1, DR2, DR3, DR6, and DR7) • MSR registers • RDX:RAX register pair representing a 128-bit operand |
Re: Exponent aus Extended extrahieren?
Und der Grund, warum die Register unverändert sind/bleiben;
der selbe ASM-Code soll natürlich überall das Selbe machen. was als R (bei RAX) und Co. bei 64 Bit steht, wußte ich jetzt noch nicht ... hatte nie die Zeit und Intention mal danach zu sehen :oops: , außerdem ist Commodore (das 64Bit-Delphi) ja noch nicht draußen :cry: |
Re: Exponent aus Extended extrahieren?
Zitat:
ah, jetzt wird einiges klarer :-) Danke .. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:49 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