Tut tuuut

Partagez votre expérience de PureBasic avec les autres utilisateurs.
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Tut tuuut

Message par fweil »

En espérant qu'il ne fasse pas pouët ...

Il y a un Nico de service qui a demandé qq chose au sujet des passages d'arguments par valeur et pointeur.

Le sujet et un peu plus vaste que ce qui est montré ici, mais j'ai pris le temps de rédiger un truc mignon pour les débutants et les autres. Je pense que cela permet de bien comprendre pour le cas où vous avez encore qq soucis à saisir le sujet.

Je propose de faire par la suite, moi où qui voudra ou purra bien, et sous une forme à peu près identique, des compléments à ce premier chapitre.

On ne sait jamais, des fois qu'il en sorte un bouquin et qu'on le publie !

Code : Tout sélectionner

;
; Factorielle1 reçoit la valeur n en argument  et renvoit le résultat dans Resultat
; La valeur Resultat peut être récupérée en appelant la fonction affectée à une variable :
; x = Factorielle1(12) stockera le résultat dans x
;
Procedure.l Factorielle1(n.l)
  Resultat.l = 1
  For i = n To 2 Step -1
    Resultat = Resultat * i
  Next
  ProcedureReturn Resultat
EndProcedure

;
; Factorielle2 reçoit non pas une valeur, mais un pointeur
; De ce fait il faut récupérer la valeur de manière indirecte
; Cette adressage indirect permet de connaître l'emplacement mémore
; de la variable, et par conséquent de placer le résutlat de la fonction
; à cet emplacement.
;
; On ne peut pas utiliser cette fonction sous la forme x = Factorielle(8), mais
; uniquement sous la forme x = 8 : Factorielle(x) : ...
;
Procedure Factorielle2(*Pointeur.l)
  Valeur.l = PeekL(*Pointeur)
  Resultat.l = 1
  For i = Valeur To 2 Step -1
    Resultat = Resultat * i
  Next
  PokeL(*Pointeur, Resultat)
EndProcedure

;
; Factorielle3 permet d'avoir le résultat placé dans la variable et en valeur de retour de la fonction
; Il arrive que certaines fonctions disposent de ux modes de retour de valeur, facilitant ainsi l'accès
; pour les programmeurs.
;
; On peut utiliser cette fonction indifférement sous la forme : x = Factoriel(n) ou bien x = 8 : Factorielle(x) : ...
; Mais attention x prend la valeur résultat dans les deux cas et ne peut pas être récupéré à sa valeur initiale sans
; stockage dans une autre variable !
;
Procedure Factorielle3(*Pointeur.l)
  Valeur.l = PeekL(*Pointeur)
  Resultat.l = 1
  For i = Valeur To 2 Step -1
    Resultat = Resultat * i
  Next
  PokeL(*Pointeur, Resultat)
  ProcedureReturn Resultat
EndProcedure

Structure ENTIERLONG
  EntierLong.l
EndStructure

;
; Factorielle4 dispose des même propriétés que Factorielle3 mais utilise une structure pour permettre
; d'avoir une équivalence pointeur / valeur. La structure est constituée d'un seul membre : un entier long.
; Ce procédé permet de faire l'économie des fonctions PeekL et PokeL et fait gagner un peu de temps.
;
Procedure Factorielle4(*Pointeur.ENTIERLONG)
  Resultat.l = 1
  For i = *Pointeur\EntierLong To 2 Step - 1
    Resultat = Resultat * i
  Next
  *Pointeur\EntierLong = Resultat
EndProcedure

;
; Pour vous permettre de réaliser des tests de performances corrects, vous devez fermer l'option Débogueur.
; A défaut le temps d'exécution peut s'avérer plus long.
;
OpenConsole()
PrintN("Test des procédures")
PrintN("")
n = 10 : PrintN("Factorielle1 : " + Str(Factorielle1(n)) + " " + Str(n))
n = 10 : PrintN("Factorielle2 : " + Str(Factorielle2(@n)) + " " + Str(n))
n = 10 : PrintN("Factorielle3 : " + Str(Factorielle3(@n)) + " " + Str(n))
n = 10 : PrintN("Factorielle4 : " + Str(Factorielle3(@n)) + " " + Str(n))

PrintN("Test de performance")
PrintN("")
Count = 10000000
tz = ElapsedMilliseconds() : For i = 1 To Count : n = 10 : o = Factorielle1(n) : Next : PrintN(Str(ElapsedMilliseconds() - tz))
tz = ElapsedMilliseconds() : For i = 1 To Count : n = 10 : o = Factorielle2(@n) : Next : PrintN(Str(ElapsedMilliseconds() - tz))
tz = ElapsedMilliseconds() : For i = 1 To Count : n = 10 : o = n : o = Factorielle3(@o) : Next : PrintN(Str(ElapsedMilliseconds() - tz))
tz = ElapsedMilliseconds() : For i = 1 To Count : n = 10 : o = n : o = Factorielle4(@o) : Next : PrintN(Str(ElapsedMilliseconds() - tz))

;
; Les tests de performances montrent rapidement une chose, c'est le coût en terme de temps, de l'appel par pointeur, qui est plus
; important que l'appel par valeur.
;
; Ce surcoût est tout simplement du au fait qu'il faut transférer la valeur de manière indirecte pour Factorielle2 et Factorielle3.
;
; Tout est question de forme !
;


While Inkey() = "" : Wend
CloseConsole()
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Mon anglais n'étant pas bon, je voulais savoir (ça fait du bien de parler français) s'il était possible avec Pure basic d'utiliser les pointeurs sur fonction, c'est à dire de passer en argument une fonction comme en language C.

Je pense que non!

:)
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Message par fweil »

Si je lis bien ceci (je parle mieux anglais que C moi !)

int resultat (int a, int b, Int (*compare)())
{
Return (compare(a, b));
}

int Max(int a, int b)
{
printf("Avec max/n");
Return((a>b) ? a:b);
}

int Min(int a, int b)
{
printf("Avec min\n");
Return((a<b) ? a:b);
}

void main(void)
{
int result;
result=resultat( 1, 2, &Max);
printf("Max de 1 et 2 = %d\n", result);
result=resultat( 1, 2, &Min);
printf("Min de 1 et 2 = %d\n", result);
}

Cela consiste à retourner le plus petit de a ou b ou de la valeur de la fonction ?
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

result=resultat( 1, 2, &Max)

ici on appelle la procédure resultat avec pour valeur 1, 2 et l'adresse de procedure de Max

ensuite cette procédure appelle la fonction pointer par *compare avec pour arguments les valeurs 1 et 2 .

ce qui donne:
Return (compare(a, b)) = Return (Max(1, 2))

ou

Return (compare(a, b)) = Return (Min(1, 2))

si j'appelle result=resultat( 1, 2, &Min)

C'est très intéressant, j'espère qu'il sera possible de le faire bientôt!

:)
Avatar de l’utilisateur
cederavic
Messages : 1338
Inscription : lun. 09/févr./2004 23:38
Localisation : Bordeaux

Message par cederavic »

c'est faisable ;) mais comme m'avais dit fred, normalement c'est pa fait pour, c'est un des pti truc sou windows, donc il faut en profiter!!! (pas si null que ça window hein :p, ouai bon... :lol: )

Code : Tout sélectionner

procedure test1(proc.l)
  callfunctionfast(proc, "blabl")
endprocedure

procedure test2(t.s)
  messagerequester(t, t, 0)
endprocedure

test1(@test2())
;)
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

...
Dernière modification par Dr. Dri le lun. 10/oct./2005 9:41, modifié 1 fois.
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

pour reprendre l'exemple plus haut

Code : Tout sélectionner

Procedure resultat(a.l,b.l,proc.l) 
  ProcedureReturn CallFunctionFast(proc,a,b) 
EndProcedure 

Procedure Max(a.l,b.l) 
  If a>b
    ProcedureReturn 1
  Else
    ProcedureReturn 0
  EndIf  
EndProcedure 

Procedure Min(a.l,b.l) 
  If a<b
    ProcedureReturn 1
  Else
    ProcedureReturn 0
  EndIf 
EndProcedure 

Debug resultat(1,2,@Max()) 
Debug resultat(1,2,@Min())
Debug "-----------------"
Debug resultat(2,1,@Max()) 
Debug resultat(2,1,@Min())
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

@Cedravic 8) :D Merci
et
@Comtois 8) :D Merci


@Dr. Dri
j'ai vu tes procédures qui sont des passages de paramètres par référence
Je les utilise moi aussi
A voir pour apprendre plus sur les pointeurs!

:)
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

...
Dernière modification par Dr. Dri le lun. 10/oct./2005 9:42, modifié 1 fois.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

@fweil

Très intéressant tes tests, j'avais justement essayer de voir la différence entre une copie de fichier avec *pointeur.byte et un PokeB sur un fichier de 5 Mega mais je n'avais pas une grosse différence!

Mais bon le programme ne se résumait pas seulement à ça!

:)
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Bon, j'en ai retaper un pour voir:

Code : Tout sélectionner

;Test de vitesse entre PokeB(...) et *pointeur\byte=... 
;sur un fichier de 7.88 Mega Octet
; Moyenne sur trois essais pour PokeB:            0.15+0.151+0.18 = 0.481
; Moyenne sur trois essais pour *pointeur\byte:   0.13+0.15+0.141 = 0.421
;sur un athlon 1.5 Ghz

Structure Valeur_Byte
  byte.b
EndStructure

file$=OpenFileRequester("Choisir un raccourci", "fichier", "*.exe", 0)

If OpenFile(0,file$)
  Longueur=Lof()
  *pointeur1=AllocateMemory(Longueur)
  *pointeur11.b=*pointeur1
  ReadData(*pointeur1,Longueur)
  
  If CreateFile(1,"c:\copie.exe")
    *pointeur2=AllocateMemory(Longueur)
    *pointeur22.b=*pointeur2           ;supprimer bloc de commentaire pour choix 1
    ;*pointeur22.Valeur_Byte=*pointeur2 ;supprimer bloc de commentaire pour choix 2
    time = GetTickCount_() 
    For a =1 To Longueur
      valeur=PeekB(*pointeur11)
      PokeB(*pointeur22,valeur) ;supprimer bloc de commentaire pour choix 1
      ;*pointeur22\byte=valeur   ;supprimer bloc de commentaire pour choix 2
      *pointeur11=*pointeur11+1
      *pointeur22=*pointeur22+1
    Next a
    Time$ = StrF((GetTickCount_()- time)/1000)
    WriteData(*pointeur2, Longueur) 
    CloseFile(1)
  EndIf
  CloseFile(0)
EndIf
 
MessageRequester("Info",Time$)
End
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

...
Dernière modification par Dr. Dri le lun. 10/oct./2005 9:42, modifié 1 fois.
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Message par fweil »

Nico,

Ton code de test sur disque est bon. Je ne sais pas ce que tu veux vérifier précisément et dans quel code cela s'insère, mais en principe tu peux chercher à avoir les meilleurs temps de lecture / écriture enchainées.

En principe, pour tester cela correctement, il faut prendre un fichier d'au moins 10MB, même plus.

Ce genre de test se fait en prenant une granularité de buffer variable, et en essayant des tailles de buffer différentes pour voir ce qui convient le mieux au système.

Autant que la mémoire le permette, ce qui est le + rapide est actuellement le transfert par buffers de la taille du fixhier, probablement jusqu'à des segments de 16MO. Après il est possible que des tailles plus grandes ne gagnent pas à être traitées en buffer + grand, d'autant que ça risque vraiment de poser des problèmes de méoire disponible sur certaine machines.

Sauf erreur de ma part pour un fichier d'une dizaine de MO, le temps de copie en un bloc doit (lecture + écriture dans le fichier de sauvegarde) être inférieur à 100 ms (taux de transfert réel de l'ordre de 100MO ce qui est d'ailleurs proprement impressionant).

Si il doit y avoir un traitement en mémoire avant sauvegarde, le principe du chargement dans un buffer unique reste intéressant même si il oblige à adresser les octets du buffer.

En tout cas on peu systématiser le remplacement des Peek et Poke parce que à coup sur on est pas forcément plus rapide, mais on est plus lisible à mon sens.

L'utilisation de l'option /COMMENTED du compilateur est intéressante pour constater combien il n'est pas possible de coder mieux que cela.

Et surtout, pour ce genre de test, NE PAS OUBLIER DE RETIRER LE DEBUGGER ! Qu'est ce que je me suis fait avoir à chercher des optimisations pour m'apercevoir que les résultats sans debugger n'étaient pas du tout les mêmes.
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Message par fweil »

Et ta calculette, toute simple est très bien écrite !
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
Répondre