Seite 1 von 1

Nutzung der FPU-80-Bit-Genauigkeit

Verfasst: 20.08.2006 01:41
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

Verfasst: 20.08.2006 09:33
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

Verfasst: 03.09.2006 14:40
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

Verfasst: 04.09.2006 21:46
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

Verfasst: 09.09.2006 04:28
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

Verfasst: 31.10.2006 15:29
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

Verfasst: 20.05.2007 21:56
von Helle
Komplett neu. Code siehe ein Posting höher.

Gruss
Helle