Ein bissel spät (mangels Zeit), aber jetzt

: Der "Fehler" tritt nur in der 32-Bit-Version auf, weil die 64-Bit-(Windows)-DDLs (benutzt von OpenWindowedScreen()) für Gleitkomma-Berechnungen SSE(2) benutzen (ADD, SUB, MUL, DIV, SQR) und nicht die FPU. Damit besteht für 64-Bit keine Notwendigkeit, die FPU zu "frisieren". Für 32-Bit bringt dies aber tatsächlich was (hatte ich vor Jahren hier mal gezeigt). Hintergrund: Die FPU wird mit Double Extended Precision (80-Bit) initialisiert (beim Einschalten, F(N)INIT), Windows (x86/x64) setzt dies auf Double Precision (64-Bit, Process/Thread). Diese Precision-Einstellung, eingestellt im FPU Control-Register (Bit 8 und 9), wird von Windows beibehalten, egal, ob Single (32-Bit)- oder Double (64-Bit)-Precision berechnet werden soll. Programme können dies aber verändern, um mehr Speed rauszuholen. Wird für Single-Precision im Programm die FPU-Precision von Double (eben eigentlich die Dauer-Einstellung) auf Single geändert, geht die Sache flotter zur Sache. Mist ist nur, wenn dies nicht wieder zurückgestellt wird.
Hier zur Erläuterung einige Beispiele:
Code: Alles auswählen
;- PB v5.00 (x64)
;- FPU-CONTROL-REGISTER:
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
; | | IC | RC | PC | | | P | U | O | Z | D | I |
; +--------------+----+---------+---------+----+----+----+----+----+----+----+----+
;- PC: Precision Control; aktuell eingestellte Genauigkeit:
; 00b = 0 = Single Precision
; 01b = 1 = Reserviert
; 10b = 2 = Double Precision
; 11b = 3 = Double Extended Precision
CWO.w ;FPU_Control_Word_Original
CWN.w ;FPU_Control_Word_Neu
AF.f = 12345.0 ;Variablen für Tests
BF.f = 67890.0
CF.f
EF.f
AD.d = 12345.0
BD.d = 67890.0
CD.d
ED.d
Procedure SetSingleFloat()
!fstcw [v_CWO] ;Control-Word sichern
!mov ax,[v_CWO]
!and ax,1111110011111111b ;die beiden Präzisions-Bits auf %00 setzen = Single-Precision
!mov [v_CWN],ax
!fldcw [v_CWN] ;verändertes Control-Word zurückschreiben
EndProcedure
Procedure SetDoubleFloat()
!fstcw [v_CWO] ;Control-Word sichern
!mov ax,[v_CWO]
!and ax,1111110011111111b ;die beiden Präzisions-Bits löschen (falls es z.B. Double Extended Precision = %11 war)
!or ax,0000001000000000b ;die beiden Präzisions-Bits auf %10 setzen = Double-Precision
!mov [v_CWN],ax
!fldcw [v_CWN] ;verändertes Control-Word zurückschreiben
EndProcedure
Procedure RestoreCW()
!fldcw [v_CWO] ;ursprüngliches Control-Word zurückschreiben
EndProcedure
;-------- Info aktuelle Einstellung
!fstcw [v_CWO]
Prec.i = (CWO >> 8) & %11
Select Prec
Case 0
P$ = "Single"
Case 2
P$ = "Double"
Case 3
P$ = "Double Extended"
EndSelect
MessageRequester("Aktuelle Einstellung FPU-Precision", P$ + "-Precision")
;-------- Test mit "Original"-Einstellungen, z.B. direkt nach PB-Start
Time = ElapsedMilliseconds() ;reicht für diese Demo aus
For i = 0 To 99999999
CF = AF * BF ;irgendeine Rechnerei
EF = Sqr(CF / AF + BF)
Next
Time1 = ElapsedMilliseconds() - Time
S1$ = "Test Original Single-Precision: " + Str(Time1) + " ms = " + StrF(EF) + #LFCR$
MessageRequester("Test Single-Precision Original", S1$)
;-------- Test mit Setzen auf Single-Precision
SetSingleFloat()
Time = ElapsedMilliseconds()
For i = 0 To 99999999
CF = AF * BF ;irgendeine Rechnerei
EF = Sqr(CF / AF + BF) ;manche Rechenoperationen bringen viel, manche weniger, richten aber keinen Schaden an!
Next
Time2 = ElapsedMilliseconds() - Time
S2$ = "Test Single-Precision gesetzt: " + Str(Time2) + " ms = " + StrF(EF) + #LFCR$
MessageRequester("Test Single-Precision gesetzt", S1$ + S2$)
;spätestens jetzt müsste die Ausgangsstellung wieder hergestellt werden, für nachfolgenden Test aber lassen wir es
;-------- Test mit Double, FPU noch mit Einstellung Single-Precision
Time = ElapsedMilliseconds()
For i = 0 To 99999999
CD = AD * BD ;irgendeine Rechnerei
ED = Sqr(CD / AD + BD)
Next
Time3 = ElapsedMilliseconds() - Time
S3$ = "Test Double, Single gesetzt: " + Str(Time3) + " ms = " + StrD(ED) + #LFCR$
MessageRequester("Test Double-Precision mit Single-Precision gesetzt", S1$ + S2$ + S3$)
RestoreCW() ;spätestens jetzt wieder Ausgangsstellung herstellen
;-------- Test mit Double, FPU mit Einstellung Double-Precision
SetDoubleFloat()
Time = ElapsedMilliseconds()
For i = 0 To 99999999
CD = AD * BD ;irgendeine Rechnerei
ED = Sqr(CD / AD + BD)
Next
Time4 = ElapsedMilliseconds() - Time
S4$ = "Test Double, Double gesetzt: " + Str(Time4) + " ms = " + StrD(ED)
MessageRequester("Test Double-Precision mit Double-Precision gesetzt", S1$ + S2$ + S3$ + S4$)
RestoreCW() ;wieder Ausgangsstellung herstellen
Viel Spaß!
Helle