Je crois que je viens de comprendre, quand on laisse des valeurs sur la pile, les instructions de chargement ne sont pas exécutées, d'où un gain de temps. Chaque registre à une étiquette qui spécifie si d'emplacement est vide. Ces étiquettes sont modifiées lorsque l'on ajoute ou retire une valeur de la pile ou avec un "FFREE registre". J'ai donc cherché ailleurs... J'ai compté le nombre d'itérations des boucles "While t > 0": pour la version PureBasic 126 et pour la version ASM 1374. Donc c'est normal que PureBasic est plus rapide. La version PureBasic utilise une variable 64 bits alors que la version ASM utilise un registre 80 bits. C.Q.F.D.
Code : Tout sélectionner
Procedure.f Exp_PB(x.f)
Protected i.l = 1, n.d, u.d, m.d = 1, t.d = 1, r.d, cmp.l = 0
n = Round(Abs(x) / Log(2), 0)
u = Abs(x) - n * Log(2)
cmp = 0
While t > 0
cmp + 1
t * u / i
i + 1
m + t
Wend
Debug cmp
r = m
While n > 0
r + r
n - 1
Wend
If x < 0
r = 1.0 / r
EndIf
ProcedureReturn r
EndProcedure
Procedure.f Exp_ASM(x.f)
Protected i.l, cmp.l=0
!NewCW equ p.v_i+0
!OldCW equ p.v_i+2
;charge x sans s'occuper du signe
!FLD dword [p.v_x]
!FABS
;n = x / Log(2)
!FLDLN2
!FDIVR ST0, ST1
;récupère le CW
!FNSTCW word [NewCW]
!FNSTCW word [OldCW]
;crée le CW pour arrondi par défaut
!AND word [NewCW], $F3FF
!OR word [NewCW], $0400
!FLDCW word [NewCW]
;n = Floor(n)
!FRNDINT
;restore le CW
!FLDCW word [OldCW]
;u = x - n * Log(2)
!FXCH
!FLD ST1 ;charge n
!FLDLN2
!FMULP
!FSUBP
;m = Exp(u)
!FLD1 ;m
!FLD1 ;t
!MOV dword [p.v_i], 1
exp_loop:
;tant que t > 0
!INC dword [p.v_cmp]
!FTST
!FNSTSW ax
!TEST ah, $40
!JNE l_exp_end_loop
;t * u / i
!FMUL ST0, st2
!FIDIV dword [p.v_i]
;i + 1
!INC dword [p.v_i]
;m + t
!FADD ST1, ST0
!MOV Eax, dword [p.v_cmp]
!CMP Eax, 126
!JNZ l_exp_loop
exp_end_loop:
Debug cmp
!FSTP ST0 ;retire t
!FSTP ST1 ;retire u
!FSCALE ;r = m * Pow(2, n)
!FSTP ST1 ;retire n
;si x négatif
!TEST dword [p.v_x], $80000000
!JE l_exp_end
;r = 1.0 / r
!FLD1
!FDIVRP
exp_end:
!ADD Esp, 8
!RET 4
EndProcedure
Debug Exp_PB(23)
Debug "------"
Debug Exp_ASM(23)
;End
;- Debut du test
Global r.f
Global MonTest.ITest = New_Test(0)
For t=0 To #ITest
MonTest\Start(1)
r = Exp_PB(23)
MonTest\Stop(1)
Next
MonTest\SetTitle(1, "Méthode PureBasic = "+StrF(r))
;/
For t=0 To #ITest
MonTest\Start(2)
r = Exp_ASM(23)
MonTest\Stop(2)
Next
MonTest\SetTitle(2, "Méthode ASM = "+StrF(r))
;/
For t=0 To #ITest
MonTest\Start(3)
MonTest\Stop(3)
Next
MonTest\SetTitle(3, "A vide")
MonTest\Display(1)
P.S : Le compteur d'instruction du processeur ne fait pas la différence entre les fonctions. Il compte toutes les instructions qu'il exécute. Les différences viennent du multitâche...