Nutzung der FPU-80-Bit-Genauigkeit

Fragen zu allen anderen Programmiersprachen.
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Nutzung der FPU-80-Bit-Genauigkeit

Beitrag von Helle »

Hier mal ein kleines Beispiel zum Thema:

Code: Alles auswählen

;Beispiel für Nutzung der 80-Bit-Rechengenauigkeit der FPU.
;Zeigt auch den Umgang mit FAsm´s tword.
;Das Rechenergebnis wird hier als gepackte BCD-Zahl in den
;Speicher geschrieben.
;Brauchbar z.B. wenn bei Eingabe von Gleitkomma-Zahlen als 
;Ergebnis eine (genaue, max.18-stellige) Ganzzahl o.K.ist.
;Auf Sicherung der Umgebung wurde für diese Demo verzichtet!!!
;"Helle" Klaus Helbing 20.08.2006  PB4.0 

Global x.b

Memory.l = AllocateMemory(20)     ;20 Bytes für 2 twords 
  !mov esi,[v_Memory]

  !Macro writetw value            ;schreibt ein tword in den Speicher
  !{virtual at 0                  ;virtual ist eine FAsm-Direktive!
  !  dt value 
  !  local lo, mi, hi 
  !  load lo dword from 0 
  !  load mi dword from 4 
  !  load hi word from 8 
  ! End virtual 
  !mov dword[esi],lo
  !mov dword[esi+4],mi
  !mov word[esi+8],hi} 
   
  !writetw 123456789012345678.0   ;1.Wert übergeben 
  !add esi,10            
  !writetw 234567890123456789.0   ;2.Wert
                                  ;es können auch Nachkomma-Stellen
                                  ;angegeben werden! Das Ergebnis wird
                                  ;ganzzahlig gerundet
  !fninit                       
  !fld tword[esi-10] 
  !fld tword[esi] 
  !faddp                          ;oder andere Berechnungen, hier Addition
  !fbstp tword[esi]               ;Abspeicherung als gepackte BCD-Zahl
                                  ;ergibt eine Ganzzahl mit 18 Stellen
  !mov edi,8                      ;9 ist Byte für Vorzeichen, hier für 
Noch:                             ;Beispiel uninteressant
  !mov bl,[esi+edi]               ;die Ziffern auslesen
  !mov bh,bl
  !and bh,0f0h
  !shr bh,4
  !mov [v_x],bh
 Z$=Z$+Str(x)
  !and bl,0fh
  !mov [v_x],bl  
 Z$=Z$+Str(x)     
  !dec edi
  !jns l_noch

MessageRequester("80-Bit-BCD","   123456789012345678.0"+#CRLF$+"+ 234567890123456789.0"+#CRLF$+"= "+Z$+#CRLF$+"Im Gegensatz zu allen anderen Floating-Point-"+#CRLF$+"Berechnungs-Möglichkeiten stimmt hier das Ergebnis!")
Gruss
Helle
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Beitrag von DarkDragon »

Hallo,

Mich freut es mal einen Beweis für die 80 Bit Variablen zu sehen. Meine Lehrer wollen es mir einfach nicht glauben, dass es soetwas gibt.

MfG,
Daniel
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Hier weiterer Code zum Thema. Bei der Umrechnungs-Prozedur Float in String habe ich mich etwas verzettelt, deshalb sind z.Z. nur Werte zwischen 1 und (fast) 2 anzeigbar. Ist aber in Arbeit, Berechnungen sind davon nicht betroffen.

Code: Alles auswählen

;Rechnen mit 80-Bit-Float (das was die FPU hergibt)
;Dazu: Konvertierung von 80-Bit-Float-Zahlen (Hex) in einen PB-String
;Aufbau der 80-Bit: Bit  79    : Vorzeichen s, gesetzt = Minus
;                   Bits 78-64 : Exponent e        
;                   Bit  63    : Kennung i      
;                   Bits 62-0  : Mantisse m
;0, wenn i=0 und e=0 und m=0 
;z=(-1)^s*(i.m)*2^(e-16383)
;"Helle" Klaus Helbing, 03.09.2006, PB4.0
;
;Da es in PB (noch) keine 10-Byte-Variablen gibt wird hier mit Zeigern auf die eigentlichen
;Variablen-Adressen gearbeitet. Z1 z.B. zeigt auf die Adresse, ab der das TWord Zt1 im 
;von PB reservierten Speicher liegt. Z1 zeigt also nicht auf die FAsm-Variable Zt1! Die wird
;z.B. zur einfachen Wert-Belegung benötigt.
;Z1 usw. werden global im PB-Code definiert, Zt1 usw. werden in der data-section (unten)
;definiert und bei Bedarf mit einen Startwert belegt. 
;Auf div. Sicherungen wurde verzichtet! 
;Dieser Test arbeitet vorerst nur mit einer Bildschirm-Ausgabe zwischen 1 und 1,999999...
;Die komplette Bandbreite ist in Arbeit! 

Global X1.b
Global MH.l
Global ML.l
Global Convert$
Global Memory.l
Global Convert.l        ;Memory-Zeiger für Konvertierung 80-Bit-Float zu Dezimal
Global Dummyt1.l        ;Parameter für 80-Bit-Division
Global Dummyt2.l
Global Dummyt3.l

Global T1.f = 15.4      ;für Test mit PB
Global T2.f = 13.8
Global T3.d = 15.4 
Global T4.d = 13.8

;-------- frei wählbare Variablen-Namen, aber Werte wie hier gezeigt
;- Z1 z.B. beinhaltet den PB-Zeiger auf die in den von PB reservierten
;- Speicher umkopierte FAsm-TWord-Variable Zt1
Global Z1.l=128         ;sind Zeiger in Memory, Aus Alignment-Gründen 16 Bytes (benötigt
Global Z2.l=144         ;werden ja nur 10)
Global Z3.l=160
Global Z4.l=176
Global Z5.l=192         ;Z1-Z3 für Test Division und Z4-Z5 für Test Wurzel 2
Global Z6.l=208         ;für Test Multiplikation
;usw. bei Bedarf

;-------- Programm-Beginn
Memory = AllocateMemory(1000)     ;die ersten 128 Bytes für Procedure FPUtoDec. Wert anpassen!

;-------- Variablen mit Startwert initialisieren (wenn benötigt) ----  
!mov esi,[v_Memory]
!fninit

!mov edi,[v_Z1]         ;hier für Divisions-Test
!fld [Zt1]
!fstp tword[esi+edi]    ;schreibt den Wert des FAsm-TWords Zt1 der FAsm-Data-Section in das von PB
                        ;bereitgestellte Memory   
!mov edi,[v_Z2]
!fld [Zt2]
!fstp tword[esi+edi]

!mov edi,[v_Z4]         ;für Test Wurzel 2. Z4=176
!fld [Zt4]              ;TWord 2.0 laden 
!fstp tword[esi+edi]    ;also: ab Memory+176 steht jetzt als TWord der Wert 2.0 
                        ;beim Test (unten) wird dann in Memory+192 das Ergebnis geschrieben
                        ;(als TWord) und kann als Variable Zt5 (über Zeiger Z5)
                        ;bei Bedarf weiterverwendet werden 
;--------------------------------------------------------------------

Procedure.s FPUtoDec(Convert)
;- Dient nur zur Bildschirm-Ausgabe, hat mit Berechnungen nichts zu tun! 
;- Wegen Test der Zwischenergebnisse hier die umfangreiche Version 
 Convert$=""
  !mov esi,[v_Memory] 

;-------- Clear Memory 128 Byte komplett! Nicht nur Summenwerte!
  !mov ecx,32
  !xor eax,eax
  !mov ebx,eax
CLMEM:  
  !mov [esi+ebx],eax
  !add ebx,4
  !dec ecx
  !jnz l_clmem 
  
  !mov edi,[esp+4]      ;Adresse des zu konvertierenden Wertes einlesen
 
;-------- Vorzeichen und Exponent 
  !mov cx,[esi+edi+8]   ;Vorzeichen und Exponent            
  !and cx,cx            ;Test, ob MSB (Bit15) gesetzt ist
  !jns l_w00            ;nein, Vorzeichen ist plus
  !push ecx 
 Convert$=Convert$+"-"
  !pop ecx
  !and cx,7fffh         ;Vorzeichen-Bit löschen
W00:  
  !sub cx,16383         ;Bias ("Versatz") subtrahieren, um "echten"
                        ;Exponenten (auf Zweier-Basis) zu erhalten

;-------- Die 64-Bit-Mantisse einlesen  
  !mov eax,[esi+edi]
  !mov [v_ML],eax       ;Mantisse Low-Anteil
  !mov eax,[esi+edi+4]
  !mov [v_MH],eax       ;Mantisse High-Anteil

;-------- Auswertung  
;-------- Fall 1: Exponent = -16383, d.h. von FPU als Null zurückgegeben 
  !cmp cx,-16383        ;Exponent
  !jne l_w01
  !or eax,eax           ;MH  da der Sinn nicht die Exponential-Darstellung ist könnte auch hier abgebrochen werden
  !jnz l_w01            ; d.h. Wert auch Null  
  !cmp [v_ML],0
  !jnz l_w01
 Convert$="0.0"               ;Ergebnis ist Null
  !jmp l_w9             ;Ende
;-------- Ende Fall 1 
  
;-------- Fall 2: Exponent = 0, d.h. Zahl liegt zwischen 1 und 1.9999999.....
W01: 
  !cmp cx,0             ;Exponent Null?
  !ja l_eplus           ;nein, grösser
  !jb l_eminus          ;nein, kleiner
  !shl eax,2            ;2 plus pos.Exponent  i und die 0.5-Stelle werden verschoben
  !mov [v_MH],eax       ;verbleibender High-Anteil der Mantisse   
  !jnc l_w02            ;Test auf den 0.5-Stellenwert, wurde als letzter "geschoben"
  !mov byte[esi+65],5
W02: 
 Convert$=Convert$+"1."             ;irgendwelche Pushs nicht nötig
  !mov byte[esi+1],5    ;Startwert für Mantissenberechnung (0.5 für 2^-1)
 
;-------- Berechnung des Mantissen-Wertes und Darstellung im Dezimal-Format
;- Als Zahlenwerte werden ungepackte BCD´s verwendet (1 Byte = eine Dezimal-Ziffer)
;- Die dezimale Division durch 2 wird als Addition mit Stellenverschiebung nach rechts realisiert
  !mov edx,1            ;zeigt auf die 5 als Startwert
W1:
  !xor ah,ah
  !mov edi,edx
W2:
  !mov ecx,4
  !mov al,[esi+edi]
  !mov bl,al
  !add al,ah 
  !xor ah,ah
W3:  
  !add al,bl
  !aaa                  ;korrigiert bei Wert grösser 9 al und inkrementiert dann ah
  !dec ecx
  !jnz l_w3
  !mov [esi+edi+1],al
  !dec edi
  !jnz l_w2
  !mov [esi+edi+1],ah   ;im Bereich von 1-63 steht der jeweilige (2^minus n) Wert

;-------- Überprüfung, ob Wert zuaddiert werden soll 
  !mov eax,[v_MH]       ;Mantisse High-Anteil
  !shl eax,1
  !mov [v_MH],eax 
  !jnc l_w5             ;Bit nicht gesetzt, also keine Wert-Änderung

  !xor ah,ah
  !mov edi,63           ;lässt sich auch noch verfeinern
W4:  
  !mov bl,[esi+edi]
  !mov al,[esi+edi+64]
  !add al,bl 
  !aaa
  !mov [esi+edi+64],al
  !add [esi+edi+63],ah
  !xor ah,ah
  !dec edi
  !jnz l_w4
W5:
  !inc edx
  !cmp edx,31
  !je l_w6
  !cmp edx,63
  !jb l_w1
  !jmp l_ausgabe
W6:
  !mov eax,[v_ML]
  !mov [v_MH],eax
  !jmp l_w1
;-------- Ende Fall 2

;-------- Fall 3: Exponent > 0 
EPLUS:

;-------- Fall 4: Exponent < 0
EMINUS:
;Fall 3 und 4 sind in Arbeit. Ziel ist sowieso, die Fälle 2, 3 und 4 zusammenzufassen
  
;-------- Ziffern für Ausgabe in String schreiben
AUSGABE: 
  !mov edi,1            ;um die "Hilfsnull" zu überspringen
W8:
  !mov al,[esi+edi+64]  ;Summe 
  !mov [v_X1],al
 Convert$=Convert$+Str(X1)
  !inc edi
  !cmp edi,20          ;max. 64 oder z.B. 20 (sinnvoll), dann vielleicht mit Rundungsroutine
  !jne l_w8             ;mit 20 ist die letzte Ziffer unsicher

W9:                     ;Einsprung für alles Null   
    ProcedureReturn Convert$ ;String-Ausgabe der 80-Bit-Float-Zahl im Dezimal-Format
  EndProcedure 
;-------- 

;- Für alle mathematischen Funktionen kann man Prozeduren nach folgendem Muster erstellen:
;- Auf Ausgleich Lade-und Pop-Befehle achten!
;-------- Division ----------
Procedure Divt(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]
  !fld tword[esi+edi]            
  !mov edi,[esp+8]  
  !fld tword[esi+edi]  
  !fdivp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;-----------------------------------------------------

;-------- Multiplikation ----
Procedure Mult(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4] 
  !fld tword[esi+edi]            
  !mov edi,[esp+8]   
  !fld tword[esi+edi]  
  !fmulp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Quadratwurzel -----
Procedure Sqrtt(Dummyt1,Dummyt2)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]  
  !fld tword[esi+edi]  
  !fsqrt
  !mov edi,[esp+8] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;-----------------------------------------------------
;usw.usf.
;-------------------------------------------------------------------------

;-------- Test mit Division, Quadrat-Wurzel aus 2 und Multiplikation
f.f = T1/T2             ;Berechnung mit 32-Bit (single) Genauigkeit
Debug "15.4 / 13.8 mit 32-Bit (single) Genauigkeit:"
Debug f

d.d = T3/T4             ;Berechnung mit 64-Bit (double) Genauigkeit
Debug "15.4 / 13.8 mit 64-Bit (double) Genauigkeit:"
Debug d

Divt(Z1,Z2,Z3)          ;Berechnung mit 80-Bit (extended) Genauigkeit, Zt3=Zt1/Zt2
FPUtoDec(Z3)            ;Ergebnis-TWord in Dezimal-Wert konvertieren 
Debug "15.4 / 13.8 mit 80-Bit (extended) Genauigkeit:"
Debug Convert$          ;Bildschirm-Ausgabe

Sqrtt(Z4,Z5)            ;Quadratwurzel aus Zt4, Ergebnis Zt5
FPUtoDec(Z5)            ;Z4 und Z5 sind Zeiger auf die eigentlichen Variablen!
Debug "Quadrat-Wurzel aus 2 mit 80-Bit-Genauigkeit:"
Debug Convert$ 

Mult(Z3,Z5,Z6)          ;und jetzt multiplizieren wir die beiden vorherigen Ergebnisse
FPUtoDec(Z6)
Debug "(15.4 / 13.8) * Quadrat-Wurzel aus 2 mit 80-Bit-Genauigkeit:"
Debug Convert$


End

;--------
!section '.data' Data readable writeable

!Zt1 dt 15.4       ;für Test Division
!Zt2 dt 13.8
!Zt3 dt  0.0
!Zt4 dt  2.0       ;für Test Quadratwurzel
!Zt5 dt  0.0
!Zt6 dt  0.0       ;für Test Multiplikation
Gruss
Helle
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Ein Zwischen-Update: Alle Ergebnisse >= 1 können jetzt angezeigt werden (und 0.0). Funktionen erweitert.

Code: Alles auswählen

;Rechnen mit 80-Bit-Float (das was die FPU hergibt)
;Dazu: Konvertierung von 80-Bit-Float-Zahlen (Hex) in einen PB-String
;Aufbau der 80-Bit: Bit  79    : Vorzeichen s, gesetzt = Minus
;                   Bits 78-64 : Exponent e        
;                   Bit  63    : Kennung i      
;                   Bits 62-0  : Mantisse m
;0, wenn i=0 und e=0 und m=0 
;z=(-1)^s*(i.m)*2^(e-16383)
;"Helle" Klaus Helbing, 05.09.2006, PB4.0
;
;Da es in PB (noch) keine 10-Byte-Variablen gibt wird hier mit Zeigern auf die eigentlichen
;Variablen-Adressen gearbeitet. Z1 z.B. zeigt auf die Adresse, ab der das TWord Zt1 im 
;von PB reservierten Speicher liegt. Z1 zeigt also nicht auf die FAsm-Variable Zt1! Die wird
;z.B. zur einfachen Wert-Belegung benötigt.
;Z1 usw. werden global im PB-Code definiert, Zt1 usw. werden in der data-section (unten)
;definiert und bei Bedarf mit einen Startwert belegt. 
;Auf div. Sicherungen wurde verzichtet! 
;Dieser Test arbeitet vorerst nur mit einer Bildschirm-Ausgabe Wert > 1
;Die komplette Bandbreite ist in Arbeit! 

Global X1.b
Global MH.l
Global ML.l
Global Convert$
Global Memory.l
Global Convert.l        ;Memory-Zeiger für Konvertierung 80-Bit-Float zu Dezimal
Global Dummyt1.l        ;Parameter für 80-Bit-Division
Global Dummyt2.l
Global Dummyt3.l
Global X4.l
Global Nachkomma.l      ;begrenzt die Ziffern-Anzahl auf 20
Global Vorkomma.q       ;nimmt die Vorkomma-Ziffern auf

;-------- frei wählbare Variablen-Namen, aber Werte wie hier gezeigt
;- Z1 z.B. beinhaltet den PB-Zeiger auf die in den von PB reservierten
;- Speicher umkopierte FAsm-TWord-Variable Zt1
Global Z1.l=128         ;sind Zeiger in Memory, Aus Alignment-Gründen 16 Bytes (benötigt
Global Z2.l=144         ;werden ja nur 10)
Global Z3.l=160
;usw. bei Bedarf

;-------- Programm-Beginn
Memory = AllocateMemory(1000)     ;die ersten 128 Bytes für Procedure FPUtoDec. Wert anpassen!

;-------- Variablen mit Startwert initialisieren (wenn benötigt) ----  
  !mov esi,[v_Memory]
  !fninit

  !mov edi,[v_Z1]       ;hier für Multiplikations-Test
  !fld [Zt1]
  !fstp tword[esi+edi]  ;schreibt den Wert des FAsm-TWords Zt1 der FAsm-Data-Section in das von PB
                        ;bereitgestellte Memory   
  !mov edi,[v_Z2]
  !fld [Zt2]
  !fstp tword[esi+edi]

;--------------------------------------------------------------------

Procedure.s FPUtoDec(Convert)
;- Dient nur zur Bildschirm-Ausgabe, hat mit Berechnungen nichts zu tun! 
;- Wegen Test der Zwischenergebnisse hier die umfangreiche Version 
 Convert$=""
  !mov [v_Nachkomma],22
  !mov esi,[v_Memory] 

;-------- Clear Memory 128 Byte komplett! Nicht nur Summenwerte!
  !mov ecx,32
  !xor eax,eax
  !mov ebx,eax
CLMEM:  
  !mov [esi+ebx],eax
  !add ebx,4
  !dec ecx
  !jnz l_clmem 
  
  !mov edi,[esp+4]      ;Adresse des zu konvertierenden Wertes einlesen
 
;-------- Vorzeichen und Exponent 
  !mov cx,[esi+edi+8]   ;Vorzeichen und Exponent            
  !and cx,cx            ;Test, ob MSB (Bit15) gesetzt ist
  !jns l_w00            ;nein, Vorzeichen ist plus
  !push ecx 
 Convert$=Convert$+"-"
  !pop ecx
  !inc [v_Nachkomma]
  !and cx,7fffh         ;Vorzeichen-Bit löschen
W00:  
  !sub cx,16383         ;Bias ("Versatz") subtrahieren, um "echten"
                        ;Exponenten (auf Zweier-Basis) zu erhalten

;-------- Die 64-Bit-Mantisse einlesen  
  !mov ebx,[esi+edi]
  !mov [v_ML],ebx       ;Mantisse Low-Anteil
  !mov eax,[esi+edi+4]
  !mov [v_MH],eax       ;Mantisse High-Anteil

;-------- Auswertung  
;-------- Fall 1: Exponent = -16383, d.h. von FPU als Null zurückgegeben 
  !cmp cx,-16383        ;Exponent
  !jne l_w01
  !or eax,eax           ;MH  da der Sinn nicht die Exponential-Darstellung ist könnte auch hier abgebrochen werden
  !jnz l_w01            ; d.h. Wert auch Null  
  !cmp [v_ML],0
  !jnz l_w01
 Convert$="0.0"         ;Ergebnis ist Null
  !jmp l_w9             ;Ende
;-------- Ende Fall 1 
   
;-------- Fall 2: Exponent >= 0
W01: 
  !and cx,cx
  !js l_eminus
  
  !xor edx,edx
  !mov edi,edx
W04:
  !shl edi,1
  !shl edx,1
  !adc edi,0  
  !shl eax,1
  !adc edx,0
W05:  
  !shl ebx,1
  !adc eax,0
  !dec cx
  !jns l_w04

  !mov [v_MH],eax
  !mov [v_ML],ebx

  !mov dword[v_Vorkomma],edx
  !mov dword[v_Vorkomma+4],edi
 
  !and eax,eax
  !jns l_w02
  !mov byte[esi+65],5
W02: 
Convert$=Convert$+StrU(Vorkomma,4)+"." 
 
 X4=Len(Convert$)
  !mov eax,[v_X4]
  !sub [v_Nachkomma],eax
 
  !mov byte[esi+1],5    ;Startwert für Mantissenberechnung (0.5 für 2^-1)
  
;-------- Berechnung des Mantissen-Wertes und Darstellung im Dezimal-Format
;- Als Zahlenwerte werden ungepackte BCD´s verwendet (1 Byte = eine Dezimal-Ziffer)
;- Die dezimale Division durch 2 wird als Addition mit Stellenverschiebung nach rechts realisiert
  !mov edx,1           ;zeigt auf die 5 als Startwert

W1:
  !xor ah,ah
  !mov edi,edx
W2:
  !mov ecx,4
  !mov al,[esi+edi]
  !mov bl,al
  !add al,ah 
  !xor ah,ah
W3:  
  !add al,bl
  !aaa                  ;korrigiert bei Wert grösser 9 al und inkrementiert dann ah
  !dec ecx
  !jnz l_w3
  !mov [esi+edi+1],al
  !dec edi
  !jnz l_w2
  !mov [esi+edi+1],ah   ;im Bereich von 1-63 steht der jeweilige (2^minus n) Wert
;-------- Überprüfung, ob Wert zuaddiert werden soll 
  !mov eax,[v_MH]       ;Mantisse High-Anteil
  !shl eax,1

  !mov ebx,[v_ML]
  !shl ebx,1
  !adc eax,0
  !mov [v_ML],ebx
  !mov [v_MH],eax 
 
  !and eax,eax
  !jns l_w5

  !xor ah,ah
  !mov edi,63           ;lässt sich auch noch verfeinern
W4:  
  !mov bl,[esi+edi]
  !mov al,[esi+edi+64]
  !add al,bl 
  !aaa
  !mov [esi+edi+64],al
  !add [esi+edi+63],ah
  !xor ah,ah
  !dec edi
  !jnz l_w4
W5:
  !inc edx
  !cmp edx,63
  !jb l_w1
  !jmp l_ausgabe
;-------- Ende Fall 2

;-------- Fall 3: Exponent < 0
EMINUS:
;Fall ist in Arbeit.
  
;-------- Ziffern für Ausgabe in String schreiben
AUSGABE: 
  !mov edi,1            ;um die "Hilfsnull" zu überspringen
W8:
  !mov al,[esi+edi+64]  ;Summe 
  !mov [v_X1],al
 Convert$=Convert$+Str(X1)
  !inc edi
  !cmp edi,[v_Nachkomma];20           ;max. 64 oder z.B. 20 (sinnvoll), dann vielleicht mit Rundungsroutine
  !jb l_w8              ;mit 20 ist die letzte Ziffer unsicher

W9:                     ;Einsprung für alles Null   
    ProcedureReturn Convert$ ;String-Ausgabe der 80-Bit-Float-Zahl im Dezimal-Format
  EndProcedure 
;-------- 

;-------- Addition ----------
Procedure Addt(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]
  !fld tword[esi+edi]            
  !mov edi,[esp+8]  
  !fld tword[esi+edi]  
  !faddp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Cosinus -----------
Procedure Cost(Dummyt1,Dummyt2)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]  
  !fld tword[esi+edi]  
  !fcos
  !mov edi,[esp+8] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Division ----------
Procedure Divt(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]
  !fld tword[esi+edi]            
  !mov edi,[esp+8]  
  !fld tword[esi+edi]  
  !fdivp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Multiplikation ----
Procedure Mult(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4] 
  !fld tword[esi+edi]            
  !mov edi,[esp+8]   
  !fld tword[esi+edi]  
  !fmulp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Pi ----------------
Procedure Pit(Dummyt1)
  !mov esi,[v_Memory] 
  !fninit                       
  !fldpi
  !mov edi,[esp+4] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------


;-------- Quadratwurzel -----
Procedure Sqrtt(Dummyt1,Dummyt2)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]  
  !fld tword[esi+edi]  
  !fsqrt
  !mov edi,[esp+8] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Sinus -------------
Procedure Sint(Dummyt1,Dummyt2)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]  
  !fld tword[esi+edi]  
  !fsin
  !mov edi,[esp+8] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Subtraktion -------
Procedure Subt(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]
  !fld tword[esi+edi]            
  !mov edi,[esp+8]  
  !fld tword[esi+edi]  
  !fsubp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;----------------------------
;usw.usf.
;-------------------------------------------------------------------------

;-------- Tests
Mult(Z1,Z2,Z3)          ;Berechnung mit 80-Bit (extended) Genauigkeit, Zt3=Zt1*Zt2
FPUtoDec(Z3)            ;Ergebnis-TWord in Dezimal-Wert konvertieren 
Debug "3891234.123456789 * 44826.54321 mit 80-Bit Genauigkeit:"
Debug Convert$          ;Bildschirm-Ausgabe

Pit(Z3)
FPUtoDec(Z3)
Debug "Pi mit 80-Bit-Genauigkeit:"
Debug Convert$


End

;--------
!section '.data' Data readable writeable

!Zt1 dt 3891234.123456789
!Zt2 dt 44826.54321
Edit 5.9.2000: Vorkomma-Anzeige verbessert.

Gruss
Helle
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Hier die Version mit kompletter Anzeige und kleinem Beispiel (Berechnung der Erdoberfläche).

Code: Alles auswählen

;Rechnen mit 80-Bit-Float (das was die FPU hergibt)
;Dazu: Konvertierung von 80-Bit-Float-Zahlen (Hex) in einen PB-String
;Aufbau der 80-Bit: Bit  79    : Vorzeichen s, gesetzt = Minus
;                   Bits 78-64 : Exponent e        
;                   Bit  63    : Kennung i      
;                   Bits 62-0  : Mantisse m
;0, wenn i=0 und e=0 und m=0 
;z=(-1)^s*(i.m)*2^(e-16383)
;"Helle" Klaus Helbing, 09.09.2006, PB4.0
;
;Da es in PB (noch) keine 10-Byte-Variablen gibt wird hier mit Zeigern auf die eigentlichen
;Variablen-Adressen gearbeitet. ZW4 z.B. zeigt auf die Adresse, ab der das TWord W4 im 
;von PB reservierten Speicher liegt. ZW4 zeigt also nicht auf die FAsm-Variable W4! Die wird
;z.B. zur einfachen Wert-Belegung benötigt.
;ZW4 usw. werden global im PB-Code definiert, W4 usw. werden in der data-section (unten)
;definiert, wenn sie mit einen Startwert belegt werden sollen. 

Global X1.b
Global MH.l             ;Mantisse High
Global ML.l             ;Mantisse Low
Global MLL.l            ;Mantisse Low Low (für Exponent <0)
Global Convert$
Global Memory.l
Global Convert.l        ;Memory-Zeiger für Konvertierung 80-Bit-Float zu Dezimal
Global Dummyt1.l        ;Parameter für 80-Bit-Operationen
Global Dummyt2.l
Global Dummyt3.l
Global X4.l
Global Nachkomma.l      ;begrenzt die Ziffern-Anzahl
Global Vorkomma.q       ;nimmt die Vorkomma-Ziffern auf

;-------- frei wählbare Variablen-Namen, aber Werte wie hier gezeigt
;hier sind alle verwendeten Variablen (genauer: Zeiger darauf) zu deklarieren
;Namen sind wie üblich frei wählbar, siehe Rechenbeispiel unten
Global ZPI.l=128        ;sind Zeiger in Memory, Aus Alignment-Gründen 16 Bytes (benötigt
Global ZW4.l=144        ;werden ja nur 10)
Global ZE1.l=160        
Global ZE2.l=176
Global ZRE.l=192
Global ZOE.l=208

;usw. für weitere Variablen

;-------- Programm-Beginn
Memory = AllocateMemory(1000)     ;die ersten 128 Bytes für Procedure FPUtoDec. Wert anpassen!

;-------- Variablen mit Startwert initialisieren (wenn benötigt) ----  
  !mov esi,[v_Memory]
  !fninit

  !mov edi,[v_ZW4]      ;über Zeiger ZW4 den Wert von W4 einlesen
  !fld [W4]
  !fstp tword[esi+edi]  ;schreibt den Wert des FAsm-TWords W4 der FAsm-Data-Section in das von PB
                        ;bereitgestellte Memory   
  !mov edi,[v_ZRE]
  !fld [RE]
  !fstp tword[esi+edi]

;--------------------------------------------------------------------

Procedure FPUtoDec(Convert)
;- Dient nur zur Bildschirm-Ausgabe, hat mit Berechnungen nichts zu tun! 
 Convert$=""
  !mov [v_Nachkomma],22
  !mov esi,[v_Memory] 

;-------- Clear Memory 128 Byte komplett! Nicht nur Summenwerte!
  !mov ecx,32
  !xor eax,eax
  !mov ebx,eax
CLMEM:  
  !mov [esi+ebx],eax
  !add ebx,4
  !dec ecx
  !jnz l_clmem 
  
  !mov edi,[esp+4]      ;Adresse des zu konvertierenden Wertes einlesen
 
;-------- Vorzeichen und Exponent 
  !mov cx,[esi+edi+8]   ;Vorzeichen und Exponent            
  !and cx,cx            ;Test, ob MSB (Bit15) gesetzt ist
  !jns l_w00            ;nein, Vorzeichen ist plus
  !push ecx 
 Convert$=Convert$+"-"
  !pop ecx
  !inc [v_Nachkomma]
  !and cx,7fffh         ;Vorzeichen-Bit löschen
W00:  
  !sub cx,16383         ;Bias ("Versatz") subtrahieren, um "echten"
                        ;Exponenten (auf Zweier-Basis) zu erhalten
  !cmp cx,64
  !jl l_egut
  !cmp cx,-64
  !jg l_egut  

;------------------------------------------------
MessageRequester("Fehler!","Ergebnis ausserhalb des Darstellungsbereiches!")

End
;------------------------------------------------

;-------- Die 64-Bit-Mantisse einlesen  
EGUT:
  !mov ebx,[esi+edi]
  !mov [v_ML],ebx       ;Mantisse Low-Anteil
  !mov eax,[esi+edi+4]
  !mov [v_MH],eax       ;Mantisse High-Anteil

;-------- Auswertung  
;-------- Test,ob Exponent = -16383, d.h. von FPU als Null zurückgegeben 
  !cmp cx,-16383        ;Exponent
  !jne l_w01
  !or eax,eax           ;MH  da der Sinn nicht die Exponential-Darstellung ist könnte auch hier abgebrochen werden
  !jnz l_w01            ;d.h. Wert auch Null  
  !cmp [v_ML],0
  !jnz l_w01
 Convert$="0.0"         ;Ergebnis ist Null
  !jmp l_w9             ;Ende
;------------------------------------------------

W01: 
  !and cx,cx
  !jns l_wnn            ;Exponent nicht negativ

;-------- Exponent <0 
  !pushad 
Convert$=Convert$+"0."
  !popad 
  !cmp cx,-1
  !jne l_w06
  !mov byte[esi+65],5
  !jmp l_w03            ;Edit: Dieser Sprung war verlustig gegangen! 9.9.2006    
W06:
  !neg cx

;-------- Versuch, eine vernünftige Ziffernanzahl für die Darstellung zu bestimmen
  !push ecx
  !mov edi,ecx
  !bsr edx,ecx
  !mov ecx,edx
  !shr edi,cl
  !dec cl
  !shl edi,cl
  !pop ecx
  !dec edi

  !add [v_Nachkomma],edi 

;------------------------ 
  !dec cx
  !xor edx,edx
W07:
  !shr edx,1
  !shr ebx,1
  !jnc l_w010 
  !or edi,80000000h
W010:
  !shr eax,1
  !jnc l_w09 
  !or ebx,80000000h
W09:
  !dec cx
  !jnz l_w07

  !mov [v_MH],eax
  !mov [v_ML],ebx
  !mov [v_MLL],edx

  !jmp l_w10

;-------- Exponent >=0 
WNN:  
  !xor edx,edx
  !mov edi,edx
W04:
  !shl edi,1
  !shl edx,1
  !adc edi,0  
  !shl eax,1
  !adc edx,0
W05:  
  !shl ebx,1
  !adc eax,0
  !dec cx
  !jns l_w04

  !mov [v_MH],eax
  !mov [v_ML],ebx

  !mov dword[v_Vorkomma],edx
  !mov dword[v_Vorkomma+4],edi
 
  !and eax,eax
  !jns l_w02
  !mov byte[esi+65],5
W02: 
Convert$=Convert$+StrU(Vorkomma,4)+"." 

W03:                    ;Einsprung von neg.Exponent   
 X4=Len(Convert$)
  !mov eax,[v_X4]
  !sub [v_Nachkomma],eax
W10:
  !mov byte[esi+1],5    ;Startwert für Mantissenberechnung (0.5 für 2^-1)
  
;-------- Berechnung des Mantissen-Wertes und Darstellung im Dezimal-Format
;- Als Zahlenwerte werden ungepackte BCD´s verwendet (1 Byte = eine Dezimal-Ziffer)
;- Die dezimale Division durch 2 wird als Addition mit Stellenverschiebung nach rechts realisiert
  !mov edx,1           ;zeigt auf die 5 als Startwert
W1:
  !xor ah,ah
  !mov edi,edx
W2:
  !mov ecx,4
  !mov al,[esi+edi]
  !mov bl,al
  !add al,ah 
  !xor ah,ah
W3:  
  !add al,bl
  !aaa                  ;korrigiert bei Wert grösser 9 al und inkrementiert dann ah
  !dec ecx
  !jnz l_w3
  !mov [esi+edi+1],al
  !dec edi
  !jnz l_w2
  !mov [esi+edi+1],ah   ;im Bereich von 1-63 steht der jeweilige (2^minus n) Wert
;-------- Überprüfung, ob Wert zuaddiert werden soll 
  !mov eax,[v_MH]       ;Mantisse High-Anteil
  !shl eax,1

  !mov ebx,[v_ML]
  !shl ebx,1
  !adc eax,0

  !mov ecx,[v_MLL]
  !shl ecx,1
  !adc ebx,0
 
  !mov [v_MLL],ecx
  !mov [v_ML],ebx
  !mov [v_MH],eax 
 
  !and eax,eax
  !jns l_w5

  !xor ah,ah
  !mov edi,63           ;lässt sich auch noch verfeinern
W4:  
  !mov bl,[esi+edi]
  !mov al,[esi+edi+64]
  !add al,bl 
  !aaa
  !mov [esi+edi+64],al
  !add [esi+edi+63],ah
  !xor ah,ah
  !dec edi
  !jnz l_w4
W5:
  !inc edx
  !cmp edx,64
  !jb l_w1
   
;-------- Ziffern für Ausgabe in String schreiben
AUSGABE: 
  !mov edi,1            ;um die "Hilfsnull" zu überspringen
W8:
  !mov al,[esi+edi+64]  ;Summe 
  !mov [v_X1],al
 Convert$=Convert$+Str(X1)
  !inc edi
  !cmp edi,[v_Nachkomma]
  !jb l_w8

W9:                     ;Einsprung für alles Null   
EndProcedure 
;-------- 

;-------- Addition ----------
Procedure Addt(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]
  !fld tword[esi+edi]            
  !mov edi,[esp+8]  
  !fld tword[esi+edi]  
  !faddp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Cosinus -----------
Procedure Cost(Dummyt1,Dummyt2)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]  
  !fld tword[esi+edi]  
  !fcos
  !mov edi,[esp+8] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Division ----------
Procedure Divt(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]
  !fld tword[esi+edi]            
  !mov edi,[esp+8]  
  !fld tword[esi+edi]  
  !fdivp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Multiplikation ----
Procedure Mult(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4] 
  !fld tword[esi+edi]            
  !mov edi,[esp+8]   
  !fld tword[esi+edi]  
  !fmulp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Pi ----------------
Procedure Pit(Dummyt1)
  !mov esi,[v_Memory] 
  !fninit                       
  !fldpi
  !mov edi,[esp+4] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Quadratwurzel -----
Procedure Sqrtt(Dummyt1,Dummyt2)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]  
  !fld tword[esi+edi]  
  !fsqrt
  !mov edi,[esp+8] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Sinus -------------
Procedure Sint(Dummyt1,Dummyt2)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]  
  !fld tword[esi+edi]  
  !fsin
  !mov edi,[esp+8] 
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;-------- Subtraktion -------
Procedure Subt(Dummyt1,Dummyt2,Dummyt3)
  !mov esi,[v_Memory] 
  !fninit                       
  !mov edi,[esp+4]
  !fld tword[esi+edi]            
  !mov edi,[esp+8]  
  !fld tword[esi+edi]  
  !fsubp st1,st0
  !mov edi,[esp+12]
  !fstp tword[esi+edi]  ;Ergebnis
EndProcedure 
;----------------------------

;----------------------------
;usw.usf.
;-------------------------------------------------------------------------

;-------- Rechenbeispiel
;Es soll die Oberfläche der Erde in m² berechnet werden
;Kugeloberfläche = 4*Pi*R*R

Pit(ZPI)                ;Wert von Pi laden
Mult(ZW4,ZPI,ZE1)       ;4*Pi in E1 speichern
Mult(ZRE,ZRE,ZE2)       ;Re*Re in E2 speichern
Mult(ZE1,ZE2,ZOE)       ;E1 mit E2 multipliziert ergibt das Ergebnis 

FPUtoDec(ZOE)           ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("80-Bit Berechnung","Erdoberfläche in m² :  " + Convert$)


End

;-------- hier sind einfach 80-Bit-Variablen mit Werten zu belegen
!section '.data' Data readable writeable

!W4 dt 4.0              ;W4 bekommt Wert 4.0
!RE dt 6371007.176      ;Radius der Erde in Meter für flächengleiche Kugel (GRS 80-Ellipsoid)
Gruss
Helle
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Was macht man an einem Feiertag mit durchwachsendem Wetter? Man überarbeitet alten verzapften Kram :D !
Edit: Komplette Überarbeitung und Erweiterung 20.05.2007:

Code: Alles auswählen

;-------- Beispiele für Anwendung 80-Bit-FPU
;-------- "Helle" Klaus Helbing, 20.05.2007, PB4.02
;-------- benötigt das Include-File Procfpu80.pbi 

;- Var1, Var2 und Var3 PB als 10-Byte-Variable unterjubeln 
Structure FPU80Bit 
 Teil1.l : Teil2.l : Teil3.l ;jeweils 12 Byte reservieren, von Teil3 werden nur 2 Bytes genutzt
EndStructure 

Define.FPU80Bit Var1, Var2, Var3  ;dem Kind einen Namen geben

;- benötigten String für die Bildschirm-Ausgabe definieren
Global Convert$ = Space(255) ;frei wählbarer Name für die Ausgabe, Grösse je nach Bedarf (was man vor hat)

;- die 80-Bit-Prozeduren laden
XIncludeFile "Procfpu80.pbi" ;oder nur benötigte Prozeduren einfügen

;- Var1 und Var2 mit 10-Byte-Floating-Point-Werten belegen 
Teststring1$ = "0.75"
ValT(@Teststring1$, Var1)
Teststring2$ = "11"
ValT(@Teststring2$, Var2)

;- Ab hier Beispiele mit den beiden Variablen Var1 und Var2 
;-------- Beispiel ArcusCosinus(0.75)
ACosT(Var1, Var3)            ;Var3 = ACos(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel ACos(0.75)","Single-Float:   "+StrF(ACos(0.75),20)+#LFCR$+"Double-Float:  "+StrD(ACos(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.72273424781341561117837735264133")

;-------- Beispiel ArcusCotangens(0.75)
ACotT(Var1, Var3)            ;Var3 = ACot(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel ACot(0.75)","Single-Float:   "+StrF((#PI/2)-ATan(0.75),20)+#LFCR$+"Double-Float:  "+StrD((#PI/2)-ATan(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.92729521800161223242851246292243")
 
;-------- Beispiel Addition 0.75 + 11.0
AddT(Var1, Var2, Var3)       ;Var3 = Var1 + Var2 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Addition 0.75+11.0","Single-Float:   "+StrF(0.75+11.0,20)+#LFCR$+"Double-Float:  "+StrD(0.75+11.0,20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   11.75")
 
;-------- Beispiel ArcusSinus(0.75)
ASinT(Var1, Var3)            ;Var3 = ASin(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel ASin(0.75)","Single-Float:   "+StrF(ASin(0.75),20)+#LFCR$+"Double-Float:  "+StrD(ASin(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.84806207898148100805294433899842")

;-------- Beispiel ArcusTangens(0.75)
ATanT(Var1, Var3)            ;Var3 = ATan(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel ATan(0.75)","Single-Float:   "+StrF(ATan(0.75),20)+#LFCR$+"Double-Float:  "+StrD(ATan(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.64350110879328438680280922871732")

;-------- Beispiel Cosinus(0.75)
CosT(Var1, Var3)             ;Var3 = Cos(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Cos(0.75)","Single-Float:   "+StrF(Cos(0.75),20)+#LFCR$+"Double-Float:  "+StrD(Cos(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.73168886887382088631183875300008")

;-------- Beispiel Cotangens(0.75)
CotT(Var1, Var3)             ;Var3 = Cot(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Cot(0.75)","Single-Float:   "+StrF(1/Tan(0.75),20)+#LFCR$+"Double-Float:  "+StrD(1/Tan(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   1.0734261485493773587431645424435")

;-------- Beispiel Division 0.75 / 11.0
DivT(Var1, Var2, Var3)       ;Var3 = Var1 / Var2 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Division 0.75/11.0","Single-Float:   "+StrF(0.75/11.0,20)+#LFCR$+"Double-Float:  "+StrD(0.75/11.0,20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.068181818181818181818181818181818")

;-------- Beispiel Multiplikation 0.75 * 11.0
MulT(Var1, Var2, Var3)       ;Var3 = Var1 * Var2 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Multiplikation 0.75*11.0","Single-Float:   "+StrF(0.75*11.0,20)+#LFCR$+"Double-Float:  "+StrD(0.75*11.0,20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   8.25")

;-------- Beispiel Laden der Konstante Pi als Beispiel für alle Konstanten (s.Procfpu80.pbi)
PiT(Var3)                    ;Var3 = Pi 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe DAS Ergebnis als String (Convert$)
MessageRequester("Beispiel Laden der Konstante Pi","Single-Float:   "+StrF(#PI,20)+#LFCR$+"Double-Float:  "+StrD(#PI,20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   3.1415926535897932384626433832795")

;-------- Beispiel Potenzierung 0.75 ^ 11.0
Powt(Var1, Var2, Var3)       ;Var3 = Var1 ^ Var2 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Potenzierung 0.75^11.0","Single-Float:   "+StrF(Pow(0.75,11.0),20)+#LFCR$+"Double-Float:  "+StrD(Pow(0.75,11.0),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.0422351360321044921875")

;-------- Beispiel Sinus(0.75)
SinT(Var1, Var3)             ;Var3 = Sin(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Sin(0.75)","Single-Float:   "+StrF(Sin(0.75),20)+#LFCR$+"Double-Float:  "+StrD(Sin(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.68163876002333416673324195277989")

;-------- Beispiel Quadratwurzel(0.75)
SqrT(Var1, Var3)             ;Var3 = Sqr(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Sqr(0.75)","Single-Float:   "+StrF(Sqr(0.75),20)+#LFCR$+"Double-Float:  "+StrD(Sqr(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.86602540378443864676372317075294")

;-------- Beispiel Subtraktion 0.75 - 11.0
SubT(Var1, Var2, Var3)       ;Var3 = Var1 - Var2 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Subtraktion 0.75-11.0","Single-Float:   "+StrF(0.75-11.0,20)+#LFCR$+"Double-Float:  "+StrD(0.75-11.0,20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   -10.25")

;-------- Beispiel Tangens(0.75)
TanT(Var1, Var3)             ;Var3 = Tan(Var1) 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Berechnungsbeispiel Tan(0.75)","Single-Float:   "+StrF(Tan(0.75),20)+#LFCR$+"Double-Float:  "+StrD(Tan(0.75),20)+#LFCR$+"80-Bit-Float:    "+Convert$+#LFCR$+"Windows-R.:   0.93159645994407246116520275657394")

;-------- Beispiel Compare
If CompT(Var1, Var2) = 0
      MessageRequester("Compare","Var1 und Var2 sind gleich")
   ElseIf Compt(Var1, Var2) = 1
      MessageRequester("Compare","Var1 ist kleiner als Var2")
   ElseIf Compt(Var1, Var2) = 2
      MessageRequester("Compare","Var1 ist grösser als Var2")
EndIf 

;-------- Beispiel Copy
CopyT(Var3, Var1)            ;kopiert Var1 in Var3
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Beispiel für Copy", "Var3 hat jetzt den Wert " + Convert$)

;-------- Beispiel Change
ChangeT(Var1, Var2)          ;vertauscht Var1 und Var2
StrT(@Convert$, Var1)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Beispiel für Change", "Var1 hat jetzt den Wert " + Convert$)
StrT(@Convert$, Var2)
MessageRequester("Beispiel für Change", "Var2 hat jetzt den Wert " + Convert$)

;-------- Beispiel Val
Teststring1$ = "0.19e4732"
ValT(@Teststring1$, Var1)
Teststring2$ = "0.11e4932"
ValT(@Teststring2$, Var2)
DivT(Var1, Var2, Var3)       ;Var3 = Var1 / Var2 
StrT(@Convert$, Var3)        ;liefert für die Bildschirm-Ausgabe das Ergebnis als String (Convert$)
MessageRequester("Beispiel für Val", "Der Quotient der beiden Teststring-Werte beträgt " + Convert$)

End

Code: Alles auswählen

;-------- Include-File Procfpu80.pbi
;-------- Bildschirm-Ausgabe und Funktionen 80-Bit-FPU
;-------- "Helle" Klaus Helbing, 20.05.2007, PB4.02
;-------- Es wurde darauf geachtet, das der TOS nach Verlassen der jeweiligen Prozedur
;-------- immer auf St(0) zeigt und St(0) leer ist


;-------- Str --------------- Variable1 = Str(Variable2) -----------------
Procedure StrT(Variable1, Variable2)
;- Dient nur zur Bildschirm-Ausgabe, hat mit Berechnungen nichts zu tun! 
;- Der 10-Byte-Float-Wert von Variable2 wird in einen String konvertiert 
;- Benötigt CPU mit SSE2!
;- Intern:
;- Fall 1: 0.00000000...        bis 0.999999999999999999939999999999
;- Fall 2: 18446744073709551616 bis ...
;- Fall 3: 1.0                  bis 18446744073709551615 (2^64-1)
;- Werte gelten auch für negative Zahlen 
;- Werte-Bereich: 80-Bit      : 2^-16382 ... 2^16384; Zifferngenau bis ca. 1.084x10^-19
;- Zum Vergleich: Single-Float: 2^-126   ... 2^128;      "     "    "   "  1.192x10^-7  
;-                Double-Float: 2^-1022  ... 2^1024;     "     "    "   "  2.220x10^-16 

  !xor eax,eax
  !mov ebx,eax
  !mov [StringZ],eax 
!@@:
  !mov dword[String1+ebx],eax
  !add ebx,4
  !cmp ebx,1024
  !jb @b

  !mov edi,[p.v_Variable2]   ;Zeiger auf umzuwandelnden String
;-------- Vorzeichen und Exponent 
  !mov cx,[edi+8]       ;Vorzeichen und Exponent            
  !and cx,cx            ;Test, ob MSB (Bit15) gesetzt ist
  !jns @f               ;nein, Vorzeichen ist plus

  !mov [StringA],2dh     ;"-"
  !mov [StringZ],1
  !and cx,7fffh         ;Vorzeichen-Bit löschen
!@@:
  !sub cx,16383         ;Bias ("Versatz") subtrahieren, um "echten" Exponenten (auf Zweier-Basis) zu erhalten

;-------- Die 64-Bit-Mantisse einlesen  
  !mov eax,[edi+4]      ;Mantisse High-Anteil
  !mov ebx,[edi]        ;Mantisse Low-Anteil
 
  !mov dword[Mantisse],ebx
  !mov dword[Mantisse+4],eax
  
;-------- Auswertung  
;-------- Test,ob Exponent = -16383, d.h. von FPU als Null zurückgegeben 
  !cmp cx,-16383        ;Exponent
  !jne @f
  !or eax,eax           ;Mantisse High-Anteil  da der Sinn nicht die Exponential-Darstellung ist könnte auch hier abgebrochen werden
  !jnz @f               ;d.h. Wert auch Null  
  !or ebx,ebx
  !jnz @f

  !mov dword[StringA],20302e30h   ;"0.0 "
  !mov edi,[p.v_Variable1]   ;Pointer auf String, in den geschrieben werden soll
  !mov ebx,4            ;4 Bytes Ausgabe
  !jmp l_merker_ende
   
;------------------------------------------------
!@@:
  !mov [Trenner],63
  !sub [Trenner],cx
  !and cx,cx
  !jns l_wnnx           ;Exponent nicht negativ

;-------- Exponent < 0 
  !mov esi,[StringZ]
  !mov word[StringA+esi],2e30h    ;"0."
  !add [StringZ],2
  
  !mov [F],5
  !mov [Merker],1
  !jmp l_ziffern_bestimmen 

;-------- Exponent >= 0 
WNNX:  
  !cmp [Trenner],0
  !jge @f
  !neg [Trenner]
  !mov [F],2            ;wenn Trenner kleiner Null wird mit 2 multipliziert!!!
  !mov [Merker],2
  !jmp l_ziffern_bestimmen 

!@@:
  !mov [F],5
  !mov [Merker],3

;-------- "String" erzeugen
Ziffern_bestimmen:
  !movq xmm0,[Mantisse] ;Ursprungswert laden
  !lea esi,[Teiler]     ;Beginn der Zehner-Potenzen
  !lea edi,[String1]    ;zum Abspeichern
  !add edi,1004
  !mov ecx,19           ;noch 19 Bytes, das 1.wird vor der Schleife gesetzt (kann nur 0 oder 1 sein)

  !movmskpd eax,xmm0    ;Test auf MSB
  !test eax,1           ;testet Bit 63!
  !jz l_w11             ;nicht gesetzt, Mantisse kleiner als 9223372036854775808 (8000000000000000h)

;- Test ob Mantisse < 10000000000000000000 
  !movq xmm1,[esi]
  !psubq xmm0,xmm1
  !movmskpd eax,xmm0    ;Test auf MSB
  !test eax,1           ;testet Bit 63!
  !jnz @f               ;kleiner als 10000000000000000000

  !mov byte[edi],1      ;"1" setzen an höchste Stelle 
  !movq [Mantisse],xmm0 ;neuer Mantissen-Wert 
  !jmp l_w11

!@@:
  !movq xmm0,[Mantisse] ;alten Mantissen-Wert wiederherstellen
 
;--------------------------------
W11:
  !inc edi              ;eine Stelle im "String" weiter
  !add esi,8
W1:
  !movq xmm1,[esi]      ;(neue) Zehner-Potenz laden
!@@:
  !psubq xmm0,xmm1      ;Mantisse minus Teiler
  !movmskpd eax,xmm0
  !test eax,1
  !jnz @f

  !movq [Mantisse],xmm0 
  !inc byte[edi]
  !jmp @b

!@@:
  !movq xmm0,[Mantisse] 
  !add esi,8 
  !inc edi
  !dec ecx
  !jnz l_w1

;- Komma ist hier auch Länge Ausgangs-String
  !mov dword[Komma],20
  !lea edi,[String1]
  !add edi,1004
  !mov ebx,20           ;Abbruch erfolgt sowieso früher
!@@:
  !cmp byte[edi],0      ;auf führende Ziffer testen
  !ja @f 
  !dec [Komma]
  !inc edi
  !dec ebx
  !jnz @b

!@@:  
  !mov eax,[Komma]
  !mov [Len],eax

  !cmp [Trenner],0
  !je l_trenner_0

  !mov ecx,1
Schleife_fuer_4:
;------- wenn F=5 Ausgangswert umkopieren für 5=4+1
  !cmp [F],5
  !jne l_w2_1
   
  !lea edi,[String1]
  !add edi,1020
  !lea esi,[String2]
  !add esi,1020
  !mov ebx,[Len] 
  !shr ebx,2
  !inc ebx              ;genug Reserve!
!@@:
  !mov eax,[edi]
  !mov [esi],eax
  !sub edi,4
  !sub esi,4
  !dec ebx
  !jnz @b
W2_1:

;-------
  !mov edx,2            ;Zähler für x4 
W1_1:                   ;für Schleife x4 
  !lea edi,[String1]
  !add edi,1023         ;Ende des Strings
  !mov ebx,[Len]
  !xor ah,ah
W0_1:                   ;für Schleife x2
  !mov al,[edi]
  !add al,al
  !add al,ah

  !xor ah,ah
  !cmp al,10
  !jb l_nicht_10
  !sub al,10
  !inc ah

  !cmp ebx,1
  !jne @f
  !inc [Len]
  !inc ebx
!@@: 

Nicht_10:
  !mov [edi],al
  !dec edi
  !dec ebx
  !jnz l_w0_1

  !cmp [F],2
  !je l_nur_2           ;nur "Multiplikation" mit 2

  !dec edx
  !jnz l_w1_1           ;zweiter Durchlauf für 2+2

;- hier 4+1 als "Multiplikation" mit 5
  !xor ah,ah
  !mov ebx,[Len]
  !lea edi,[String1]
  !add edi,1023
  !lea esi,[String2]
  !add esi,1023
W3_1:                
  !mov al,[edi]
  !mov dl,[esi]
  !add al,dl
  !add al,ah

  !xor ah,ah
  !cmp al,10
  !jb l_nicht_10_1
  !sub al,10
  !inc ah
  
  !cmp ebx,1
  !jne @f
  !inc [Len]
  !inc ebx
!@@: 

Nicht_10_1:
  !mov [edi],al
  !dec edi
  !dec esi
  !dec ebx
  !jnz l_w3_1

Nur_2:
  !cmp byte[edi+1],1
  !ja @f
  !dec [Komma]
!@@:
  !inc ecx
  !cmp cx,[Trenner]
  !jbe l_schleife_fuer_4

  !cmp byte[edi+1],2   ;wenn 2 oder grösser noch eine Stelle mehr  
  !jb @f
  !dec [Komma]
!@@:

;----------------------------------  
Trenner_0:
  !mov edi,[p.v_Variable1]   ;Pointer auf String, in den geschrieben werden soll

  !cmp [Merker],1       ;"0."
  !jne l_ob_merker2

;-------- Merker = 1 
  !movzx ecx,[Trenner] 
  !mov ebx,[StringZ]  
  !sub ecx,[Len]
  !jz l_null_1   
 
!@@:
  !mov byte[StringA+ebx],30h
  !inc ebx
  !dec ecx
  !jnz @b     
    
Null_1:
  !lea esi,[String1]
  !add esi,1024
  !mov ecx,20
  !sub esi,[Len]
!@@:
  !mov al,[esi]
  !add al,30h
  !mov [StringA+ebx],al
  !inc esi
  !inc ebx
  !dec ecx
  !jnz @b
   
  !jmp l_merker_ende 

Ob_Merker2:
  !cmp [Merker],2
  !jne l_merker3

;-------- Merker = 2  
Merker2: 
  !mov ebx,[StringZ]    ;Zeiger in StringA
  !lea esi,[String1]       
  !add esi,1024
  !mov ecx,20
  !sub esi,[Len]
!@@:
  !mov al,[esi]
  !add al,30h
  !mov [StringA+ebx],al
  !inc esi
  !inc ebx
  !dec ecx
  !jnz @b

  !mov ecx,[Len]
  !sub ecx,ebx
  !jz l_null_2

!@@:
  !mov byte[StringA+ebx],30h
  !inc ebx
  !dec ecx
  !jnz @b     
 
Null_2: 
  !jmp l_merker_ende 

;-------- Merker = 3
Merker3:
  !mov ebx,[StringZ]
  !lea esi,[String1]
  !add esi,1024
  !sub esi,[Len]
  !mov ecx,[Komma]
!@@:
  !mov al,[esi]
  !add al,30h
  !mov [StringA+ebx],al
  !inc esi
  !inc ebx
  !dec ecx
  !js @f
  !jnz @b
!@@:

  !mov ecx,20
  !sub ecx,[Komma]
  !jz l_merker_ende

  !mov [StringA+ebx],2eh
  !inc ebx
!@@:
  !mov al,[esi]
  !add al,30h
  !mov [StringA+ebx],al
  !inc esi
  !inc ebx
  !dec ecx
  !jnz @b

Merker_Ende:
  !lea esi,[StringA]
  !mov ecx,ebx
  !cld 
  !rep movsb 
  
  !mov byte[edi],0      ;für das String-Ende das Zero-Byte setzen

ProcedureReturn  

End 
 
!section '.data' Data readable writeable

!String1   RB 1024      ;eigentlicher Berechnungs-String; für Extrem-Werte ALLE String-Bezüge vergrössern! 
!String2   RB 1024      ;Hilfs-String für die Multiplikation mit 5 = 4 + 1
!StringA   RB 256       ;256 Byte für String-Ausgabe
!Mantisse  DQ 0
!Teiler    DQ 10000000000000000000
!          DQ 1000000000000000000
!          DQ 100000000000000000
!          DQ 10000000000000000
!          DQ 1000000000000000
!          DQ 100000000000000
!          DQ 10000000000000
!          DQ 1000000000000
!          DQ 100000000000
!          DQ 10000000000
!          DQ 1000000000
!          DQ 100000000
!          DQ 10000000
!          DQ 1000000
!          DQ 100000
!          DQ 10000
!          DQ 1000
!          DQ 100
!          DQ 10
!          DQ 1   
 
!F         DD 0
!Komma     DD 0
!Merker    DD 0
!StringZ   DD 0         ;Zeiger in String  StringZähler
!Len       DD 0

!Trenner   DW 0

EndProcedure 
;-------------------------------------------------------------------------


;-------- Val --------------- Variable2 = Val(Variable1) ----------------- 
Procedure ValT(Variable1, Variable2)   ;Variable1 = Zeiger auf String, Variable2 = Ausgabe
;- Grundlage: Tim Roberts und pelaillo (FAsm-Forum), 30.Dezember 2002 
;- Fehler beseitigt und an PB angepasst
;- Label-Namen wegen besserer Übersicht nicht weggekürzt (also keine "@") 
 
  !fninit
  !xor eax,eax
  !mov ebx,eax
  !mov ecx,eax
  !mov [ManVorzeichen],eax
  !mov [ExpVorzeichen],eax
  !mov [Dezimalpunkt],eax
  !mov esi,[p.v_Variable1]        
  !mov al,[esi]
  !cmp al,2dh           ;"-"
  !je l_minus_vorzeichen
  !cmp al,2bh           ;"+" Test auf pos. Vorzeichen erstmal drinlassen
  !je l_plus_vorzeichen
  !jmp l_vorzeichen_ende
Minus_Vorzeichen:
  !inc [ManVorzeichen]
Plus_Vorzeichen:
  !inc esi
  !mov al,[esi]
Vorzeichen_Ende:
  !fldz
Mantisse_Lesen:
  !cmp al,45h           ;"E"
  !je l_exponent
  !cmp al,65h           ;"e"
  !je l_exponent
  !cmp al,2eh           ;"."
  !je l_dezimal_punkt
  !xor al,30h           ;"0"
  !cmp al,9
  !ja l_ziffern_ende
  !mov [Temp],eax
  !fmul [Zehner]
  !fiadd word[Temp]
  !inc ebx
  !jmp l_kein_punkt
Dezimal_Punkt:
  !cmp [Dezimalpunkt],0
  !jne l_ziffern_ende
  !mov [Dezimalpunkt],ebx
Kein_Punkt:
  !inc esi
  !mov al,[esi]
  !jmp l_mantisse_lesen
Exponent:
  !inc esi
  !mov al,[esi]
  !cmp al,2dh           ;"-"
  !je l_minus_exponent_vorzeichen
  !cmp al,2bh           ;"+"
  !je l_plus_exponent_vorzeichen
  !jmp l_exponent_lesen
Minus_Exponent_Vorzeichen:
  !inc [ExpVorzeichen]
Plus_Exponent_Vorzeichen:
  !inc esi
  !mov al,[esi]
Exponent_Lesen:
  !xor al,30h           ;"0"
  !cmp al,9
  !ja l_ziffern_ende
  !lea ecx,[ecx*4+ecx]
  !lea ecx,[ecx*2+eax]
  !inc esi
  !mov al,[esi]
  !jmp l_exponent_lesen
Ziffern_Ende:
  !cmp [ExpVorzeichen],0
  !je l_exponent_fertig
  !neg ecx
Exponent_Fertig:
  !mov eax,[Dezimalpunkt]
  !or eax,eax
  !jz l_kein_dezimalpunkt
  !sub ebx,eax
  !sub ecx,ebx
Kein_Dezimalpunkt:
  !or ecx,ecx
  !jz l_kein_exponent
  !mov eax,ecx
  !cmp eax,0
  !jge l_exponent_vorzeichen_ok
  !neg eax
Exponent_Vorzeichen_Ok:
  !fld1
  !mov dl,al
  !and edx,0fh
  !je l_groesserer_exponent
  !lea edx,dword[edx+edx*4]
  !fld tword [edx*2+Zehner_1-10]
  !fmulp st1,st
Groesserer_Exponent:
  !mov dl,al
  !shr dl,4
  !and edx,0fh
  !je l_noch_groesserer_exponent
  !lea edx,dword[edx+edx*4]
  !fld tword [edx*2+Zehner_16-10]
  !fmulp st1,st
Noch_Groesserer_Exponent:
  !mov dl,ah
  !and edx,1fh
  !je l_exponent_vorzeichen
  !lea edx,dword[edx+edx*4]
  !fld tword[edx*2+Zehner_256-10]
  !fmulp st1,st
Exponent_Vorzeichen:
  !cmp ecx,0
  !jge l_positiver_exponent
  !fdivp st1,st
  !jmp l_kein_exponent
Positiver_Exponent:
  !fmulp st1,st
Kein_Exponent:
  !cmp [ManVorzeichen],0
  !je @f
  !fchs
!@@:
  !mov esi,[p.v_Variable2] 
  !fstp tword[esi]      ;leert damit auch den TOS

ProcedureReturn

End 

!section '.data' Data readable writeable
 
!ManVorzeichen dd 0
!ExpVorzeichen dd 0
!Dezimalpunkt  dd 0
!Temp          dd 0
!Zehner        dq 10.0
!Zehner_1      dt 1.0e1
!              dt 1.0e2
!              dt 1.0e3
!              dt 1.0e4
!              dt 1.0e5
!              dt 1.0e6
!              dt 1.0e7
!              dt 1.0e8
!              dt 1.0e9
!              dt 1.0e10
!              dt 1.0e11
!              dt 1.0e12
!              dt 1.0e13
!              dt 1.0e14
!              dt 1.0e15
!Zehner_16     dt 1.0e16
!              dt 1.0e32
!              dt 1.0e48
!              dt 1.0e64
!              dt 1.0e80
!              dt 1.0e96
!              dt 1.0e112
!              dt 1.0e128
!              dt 1.0e144
!              dt 1.0e160
!              dt 1.0e176
!              dt 1.0e192
!              dt 1.0e208
!              dt 1.0e224
!              dt 1.0e240
!Zehner_256    dt 1.0e256
!              dt 1.0e512
!              dt 1.0e768
!              dt 1.0e1024
!              dt 1.0e1280
!              dt 1.0e1536
!              dt 1.0e1792
!              dt 1.0e2048
!              dt 1.0e2304
!              dt 1.0e2560
!              dt 1.0e2816
!              dt 1.0e3072
!              dt 1.0e3328
!              dt 1.0e3584
!              dt 1.0e3840
!              dt 1.0e4096
!              dt 1.0e4352
!              dt 1.0e4608
!              dt 1.0e4864                                     

EndProcedure           
;-------------------------------------------------------------------------


;-------- ARITHMETISCHE FUNKTIONEN ---------------------------------------
;-------- Addition ---------- Variable3 = Variable1 + Variable2 ----------
Procedure AddT(Variable1, Variable2, Variable3)
  !fninit                       
  !mov esi,[p.v_Variable1]
  !fld tword[esi]            
  !mov esi,[p.v_Variable2]  
  !fld tword[esi]  
  !faddp st1,st0
  !mov esi,[p.v_Variable3]
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------

;-------- Division ---------- Variable3 = Variable1 / Variable2 ----------
Procedure DivT(Variable1, Variable2, Variable3)
  !fninit                       
  !mov esi,[p.v_Variable1]
  !fld tword[esi]            
  !mov esi,[p.v_Variable2]  
  !fld tword[esi]  
  !fdivp st1,st0
  !mov esi,[p.v_Variable3]
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------

;-------- Multiplikation ---- Variable3 = Variable1 * Variable2 ----------
Procedure MulT(Variable1, Variable2, Variable3)
  !fninit                       
  !mov esi,[p.v_Variable1] 
  !fld tword[esi]            
  !mov esi,[p.v_Variable2]   
  !fld tword[esi]  
  !fmulp st1,st0
  !mov esi,[p.v_Variable3]
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------

;-------- Quadratwurzel ----- Variable2 = Variable1 ^ 0.5 ----------------
Procedure SqrT(Variable1, Variable2)
  !fninit                       
  !mov esi,[p.v_Variable1]  
  !fld tword[esi]  
  !fsqrt
  !mov esi,[p.v_Variable2] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------

;-------- Subtraktion ------- Variable3 = Variable1 - Variable2 ----------
Procedure SubT(Variable1, Variable2, Variable3)
  !fninit                       
  !mov esi,[p.v_Variable1]
  !fld tword[esi]            
  !mov esi,[p.v_Variable2]  
  !fld tword[esi]  
  !fsubp st1,st0
  !mov esi,[p.v_Variable3]
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------


;-------- WINKELFUNKTIONEN -----------------------------------------------
;-------- ArcusCosinus ------ Variable2 = ACos(Variable1(rad)) -----------
Procedure ACosT(Variable1, Variable2)
  !fninit                       
  !fld1
  !mov esi,[p.v_Variable1]  
  !fld tword[esi]  
  !fst st2
  !fmul st0,st0
  !fsubp
  !fsqrt
  !fxch
  !fpatan
  !mov esi,[p.v_Variable2]  
  !fstp tword[esi]      ;Ergebnis
  !fdecstp
  !ffree st0
EndProcedure 

;-------- ArcusCotangens ---- Variable2 = ACot(Variable1(rad)) -----------
Procedure ACotT(Variable1, Variable2)  ;Pi/2 - arctan(x)
  !fninit                       
  !fldpi
  !fld1
  !fld1
  !faddp
  !fdivp
  !mov esi,[p.v_Variable1]   
  !fld tword[esi]  
  !fld1
  !fpatan
  !fsubp
  !mov esi,[p.v_Variable2]  
  !fstp tword[esi]      ;Ergebnis
EndProcedure 

;-------- ArcusSinus -------- Variable2 = ASin(Variable1(rad)) -----------
Procedure ASinT(Variable1, Variable2)
  !fninit                       
  !fld1
  !mov esi,[p.v_Variable1]   
  !fld tword[esi]  
  !fst st2
  !fmul st0,st0
  !fsubp
  !fsqrt
  !fpatan
  !mov esi,[p.v_Variable2]  
  !fstp tword[esi]      ;Ergebnis
  !fdecstp              ;Stack-Bereinigung, TOS ist danach ST(0)
  !ffree st0            ;ST(0) als leer deklarieren
EndProcedure 

;-------- ArcusTangens ------ Variable2 = ATan(Variable1(rad)) -----------
Procedure ATanT(Variable1, Variable2)
  !fninit                       
  !mov esi,[p.v_Variable1]    
  !fld tword[esi]  
  !fld1
  !fpatan
  !mov esi,[p.v_Variable2]  
  !fstp tword[esi]      ;Ergebnis
EndProcedure 

;-------- Cosinus ----------- Variable2 = Cos(Variable1(rad)) ------------
Procedure CosT(Variable1, Variable2)
  !fninit                       
  !mov esi,[p.v_Variable1]  
  !fld tword[esi]  
  !fcos
  !mov esi,[p.v_Variable2]  
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------

;-------- Cotangens --------- Variable2 = Cot(Variable1(rad)) ------------
Procedure CotT(Variable1, Variable2)
  !fninit                       
  !mov esi,[p.v_Variable1] 
  !fld tword[esi]  
  !fptan
  !fdivrp st1,st0
  !mov esi,[p.v_Variable2] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------

;-------- Sinus ------------- Variable2 = Sin(Variable1(rad)) ------------
Procedure SinT(Variable1, Variable2)
  !fninit                       
  !mov esi,[p.v_Variable1]  
  !fld tword[esi]  
  !fsin
  !mov esi,[p.v_Variable2] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------

;-------- Tangens ----------- Variable2 = Tan(Variable1(rad)) ------------
Procedure TanT(Variable1, Variable2)
  !fninit                       
  !mov esi,[p.v_Variable1]  
  !fld tword[esi]  
  !fptan
  !fdivp st1,st0
  !mov esi,[p.v_Variable2] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------


;-------- ERWEITERTE FUNKTIONEN ------------------------------------------
;-------- Pow --------------- Variable3 = Variable1 ^ Variable2 ----------
Procedure PowT(Variable1, Variable2, Variable3)
  !fninit                       
  !mov esi,[p.v_Variable2]
  !fld tword[esi]            
  !mov esi,[p.v_Variable1]  
  !fld tword[esi]
  !fyl2x
  !fld st0
  !frndint
  !fsub st1,st0
  !fxch st1
  !f2xm1
  !fld1
  !faddp st1,st0
  !fscale
  !fstp st1 
  !mov esi,[p.v_Variable3]
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------


;-------- KONSTANTEN -----------------------------------------------------
;-------- L0 ---------------- Variable1 = 0.0 ----------------------------
Procedure L0T(Variable1)
  !fninit                       
  !fldz                 ;00000000000000000000h = 0.0
  !mov esi,[p.v_Variable1] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure
;-------------------------------------------------------------------------

;-------- L1 ---------------- Variable1 = 1.0 ----------------------------
Procedure L1T(Variable1)
  !fninit                       
  !fld1                 ;3FFF8000000000000000h = 1.0
  !mov esi,[p.v_Variable1] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure
;-------------------------------------------------------------------------

;-------- Ld(10) ------------ Variable1 = Ld(10), 2 ^ Variable1 =10.0 ----
Procedure Ld10T(Variable1)
  !fninit                       
  !fldl2t               ;4000D49A784BCD1B8AFEh = 3.3219280948873623478
  !mov esi,[p.v_Variable1] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure
;-------------------------------------------------------------------------

;-------- Ld(e) ------------- Variable1 = Ld(e), 2 ^ Variable1 = e -------
Procedure LdeT(Variable1)
  !fninit                       
  !fldl2e               ;3FFFB8AA3B295C17F0BCh = 1.4426950408889634073
  !mov esi,[p.v_Variable1] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure
;-------------------------------------------------------------------------

;-------- Lg(2) ------------- Variable1 = Lg(2), 10 ^ Variable1 = 2.0 ----
Procedure Lg2T(Variable1)
  !fninit                       
  !fldlg2               ;3FFFB17217F7D1CF79ACh = 0.301029995663981195198
  !mov esi,[p.v_Variable1]
  !fstp tword[esi]      ;Ergebnis
EndProcedure
;-------------------------------------------------------------------------

;-------- Ln(2) ------------- Variable1 = Ln(2), e ^ Variable1 = 2.0 -----
Procedure Ln2T(Variable1)
  !fninit                       
  !fldln2               ;3FFD9A209A84FBCFF799h = 0.6931471805599453094
  !mov esi,[p.v_Variable1] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure
;-------------------------------------------------------------------------

;-------- Pi ---------------- Variable1 = Pi -----------------------------
Procedure PiT(Variable1)
  !fninit                       
  !fldpi                ;4000C90FDAA22168C335h = 3.1415926535897932385
  !mov esi,[p.v_Variable1] 
  !fstp tword[esi]      ;Ergebnis
EndProcedure 
;-------------------------------------------------------------------------


;-------- SONSTIGES ------------------------------------------------------
;-------- Change ------------ Vertauscht die Werte der beiden Variablen --
Procedure ChangeT(Variable1, Variable2)
  !fninit 
  !mov esi,[p.v_Variable1]
  !fld tword[esi] 
  !mov edi,[p.v_Variable2]
  !fld tword[edi] 
  !fstp tword[esi] 
  !fstp tword[edi] 
EndProcedure
;-------------------------------------------------------------------------

;-------- Compare ----------- Vergleicht Variable1 mit Variable2 ---------
Procedure CompT(Variable1, Variable2)
  !fninit 
  !mov esi,[p.v_Variable2]
  !fld tword[esi] 
  !mov esi,[p.v_Variable1]
  !fld tword[esi] 
  !fcompp
  !fstsw ax             ;nicht fnstsw!
  !sahf
  !jne @f               ;nicht gleich
  !xor eax,eax 
  ProcedureReturn       ;Rückgabewert=0 für Variable1 gleich Variable2
!@@:
  !jnc @f               ;nicht kleiner  
  !mov eax,1
  ProcedureReturn       ;Rückgabewert=1 für Variable1 kleiner als Variable2
!@@: 
  !mov eax,2 
  ProcedureReturn       ;Rückgabewert=2 für Variable1 grösser als Variable2
EndProcedure
;-------------------------------------------------------------------------

;-------- Copy -------------- kopiert Variable2 in Variable1 -------------
Procedure CopyT(Variable1, Variable2)
  !fninit 
  !mov esi,[p.v_Variable2]
  !fld tword[esi] 
  !mov esi,[p.v_Variable1]
  !fstp tword[esi] 
EndProcedure
;-------------------------------------------------------------------------
Gruss
Helle
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Komplett neu. Code siehe ein Posting höher.

Gruss
Helle
Antworten