Calculs en virgule flottante

Voir le sujet précédent Voir le sujet suivant Aller en bas

Calculs en virgule flottante

Message par Admin le Dim 19 Fév - 21:12

Pour commencer cette rubrique, un petit programme pour montrer des calculs en virgule flottante et qui fait appel a des fonctions de l'API pour convertir les résultats en chaines imprimables. De plus ici, on va tester la validité du générateur aléatoire (instruction rdrand) en effectuant par exemple 10000 tirages et en calculant la moyenne et l'écart type. Les résultats sont convertis de nombre en virgule flottante (float) en caractères unicode par la fonction VarBstrFromR8 puis les caractères unicode en caractères ansi par la fonction WideCharToMultiByte. Vous remarquerez que le passage d'un Float à la procédure VarBstrFromR8 s'effectue par le registre xmm0 et non pas par le registre rcx habituel (voir les conventions d'appel de l'Api Windows pour le 64 bits).
Les alignements de la pile suivent les recommandations du tutorial.
Le reste du programme ne présente pas de difficultés :
Code:

;---programme 64 bits  analyse generateur nombres aléatoires
;  calculs faits  en virgule flottante
; affichage dans la console

%include "../windowsinc64.inc"
N  equ  1000   ; plage nombres aleatoires
NBTIRAGE  equ 10000  ; nombre de tirages
;=======================================
; segment des données initialisées
;=======================================
segment .data
;code page 850 é=82h  à=85h è=8Ah ê=88h  
szChForm db "%u ",0  ; format décimal pour la fonction wsprintfA
szMessFin  db 10,13,"Fin du programme.",0
szRetourLigne db 10,13,0
szMessResult db "Moyenne = %s  ",82h,"cart type = %s",10,13,0   ; string

sAlign  align 8
iNombre  dq NBTIRAGE    ; c'est un entier
fMoyenne  dq 0.0        ; c'est un float
fDeviation  dq 0.0      ; et lui aussi
;=======================================
; segment des données non initialisées
;=======================================
segment .bss
fNombre resq 1      ; nombre de tirages converti en float
qTirage  resq 1     ; resultat du tirage entier
ptResult resq 1     ; pointeur vers les donnees converties
ITAILLEBUF  equ 100
szResult  resb ITAILLEBUF
szResultD  resb ITAILLEBUF
szResultF  resb ITAILLEBUF
;=======================================
; segment de code
;=======================================
segment .text
    global Main
 extern afferreur,affmessageP,affconsoleP,afftoutregistreP,afftoutreg8a15P,affmemoireP,affmessage,saisieClavier,vidpiles

Main:
    sub rsp, 8h     ; alignement de la pile avant tout appel de procédure
 sub rsp,20h
 ;conversion nombre de tirage en float
 finit
 fild qword [iNombre]
 fstp qword [fNombre]
 mov r12,N    ; nombre aleatoire compris entre 0 et N
 xor rbx,rbx
.boucle:
    xor rax,rax
 xor rdx,rdx
 RDRAND eax   ; generation nombre aleatoire
 div r12      ; divise par la plage voulue
 mov [qTirage],rdx ; et on garde le reste
 ; calcul en virgule flottante
 fild  qword[qTirage] ;ST0=REAL value, ST1=accumulator
 fdiv qword [fNombre] ; division de st0
 fadd qword [fMoyenne] ; ajout avec le calcul itération précedente
 fstp qword [fMoyenne]  ; stockage du résultat
 ;calcul de la deviation standard
 fild  qword[qTirage] ;ST0=REAL value, ST1=accumulator
 fmul  st0            ; multiplication par lui même
 fdiv qword [fNombre] ; division de st0
 fadd qword [fDeviation] ; ajout avec le calcul itération précedente
 fstp qword [fDeviation]  ; stockage du résultat

 inc rbx
 cmp rbx,NBTIRAGE   ; fin atteinte ?
 jne .boucle
 ;calcul final de l'ecart type
    fld qword [fMoyenne]   ; chargement de la moyenne calculée
    fmul st0             ; multiplication par elle même
 fchs                 ; inversion du signe
 fadd qword [fDeviation] ; pour la soustraire à l'écart type calcule
 fsqrt               ; racine carrée du résultat
 fstp qword [fDeviation]  ; stockage du résultat

    ; ATTENTION pour les floats il faut utiliser les registres xmm
 movsd xmm0,[fMoyenne]
 mov rdx,LOCALE_CUSTOM_DEFAULT
 mov r8,LOCALE_NOUSEROVERRIDE
 mov r9,ptResult
 call VarBstrFromR8  ; conversion du float en unicode
 mov r9,__LINE__ - 1
 cmp  eax,NULL
 jne   .gestionerreurs
 ;conversion unicode ==> Ansi
 add rsp,20h
 push NULL
 push NULL
 push ITAILLEBUF    ; taille du buffer
 push szResult
 sub rsp,20h
 mov rcx,CP_ACP
 mov rdx,WC_COMPOSITECHECK
 mov r8,[ptResult]
 mov r9,-1
 call WideCharToMultiByte ;conversion unicode ==> Ansi
 add rsp,20h
 mov r9,__LINE__ - 1
 cmp  eax,NULL
 je   .gestionerreurs
 ; ATTENTION pour les floats il faut utiliser les registres xmm
 movsd xmm0,[fDeviation]
 mov rdx,LOCALE_CUSTOM_DEFAULT
 mov r8,LOCALE_NOUSEROVERRIDE
 mov r9,ptResult
 call VarBstrFromR8  ; conversion du float en unicode
 mov r9,__LINE__ - 1
 cmp  eax,NULL
 jne   .gestionerreurs
 ;conversion unicode ==> Ansi
 add rsp,20h
 push NULL
 push NULL
 push ITAILLEBUF    ; taille du buffer
 push szResultD
 sub rsp,20h
 mov rcx,CP_ACP
 mov rdx,WC_COMPOSITECHECK
 mov r8,[ptResult]
 mov r9,-1
 call WideCharToMultiByte
 add rsp,20h
 mov r9,__LINE__ - 1
 cmp  eax,NULL
 je   .gestionerreurs
 
 ;utilisation wsprintfa pour formater le résultat
    mov rcx,szResultF   ; buffer du résultat
 mov rdx,szMessResult ; chaine de formatage
 mov r8,szResult   ; chaine de la moyenne
 mov r9,szResultD  ; chaine de l'écart type
 call wsprintfA
 mov r9,__LINE__ - 1
 cmp  eax,NULL
 je   .gestionerreurs
    push szResultF
 call affconsoleP  ; affichage du resultat dans la console

 mov rax,0
 jmp .main_fin
.gestionerreurs:
 call afferreur
 mov  rax,1
 jmp .fin
.main_fin:
    push szMessFin    ; affichage message fin
 call affconsoleP
 call saisieClavier  ; attente saisie
.fin:
 mov  rcx,rax          ; code retour
 call ExitProcess  ; fin du programme


A l'affichage des résultats, admirez la précision après la virgule !!!
avatar
Admin
Admin

Messages : 37
Date d'inscription : 28/11/2016

Voir le profil de l'utilisateur http://assembleur64.forumactif.com

Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum