LOI DE POISSON (STATS-PROBA)

yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 - 29 nov. 2006 à 15:46
pulpfrissons Messages postés 4 Date d'inscription jeudi 4 septembre 2003 Statut Membre Dernière intervention 4 avril 2008 - 4 avril 2008 à 01:45
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/40506-loi-de-poisson-stats-proba

pulpfrissons Messages postés 4 Date d'inscription jeudi 4 septembre 2003 Statut Membre Dernière intervention 4 avril 2008
4 avril 2008 à 01:45
A vouloir être trop succint, j'ai commis une petite erreur puisqu'il faut réaliser une boucle...
Qui peut le plus, peut le moins, je vous invite donc à consulter ma contribution dans la zone VB où je donne le code complet de la fonction :
http://www.vbfrance.com/codes/LOI-POISSON_46282.aspx
Encore désolé pour cette coquille...
pulpfrissons Messages postés 4 Date d'inscription jeudi 4 septembre 2003 Statut Membre Dernière intervention 4 avril 2008
4 avril 2008 à 01:43
Bonjour,

Une modeste contribution à cette source.
Sur un plan informatique, je n'ai rien à dire... parce que je ne suis pas vraiment à la hauteur des intervenants et puis parce que cela me semble très correct.
Sur un plan mathématique en revanche, je me permets de souligner un gros risque signalé par l'auteur d'ailleurs. Essayez de calculer la factorielle de 125 par exemple : vous serez déçus ! Imaginez le résultat : 1 * 2 * 3 * 4 * 5 etc *125
Peu d'ordinateurs sont capables de calculer un tel chiffre. Et ce n'est pas nécessaire !!! Vous avez tout simplement oublié les logarithmes ! Vous vous souvenez ? Le log népérien ? e ? C'est drôlement pratique quand on doit manipuler des chiffres très importants ou au contraire très faibles !
Je vous livre le code suivant (VB, désolé) mais vous ignorerez l'aspect informatique pour vous concentrer sur les maths.

dProb = exp(-moyenne)
dLogProb = -moyenne
dLogProb = dLogProb + ln(moyenne) - log(x)

Quelques explications, en bon français sont sans doute nécessaires !
Je vais prendre un exemple concret, histoire de ne pas perdre trop de monde en route.
Imaginons que l'ampoule de votre voiture tombe en panne en moyenne 3 fois dans l'année. Dans l'exemple, 3 sera la moyenne affecté à la variable appelée moyenne.
Maintenant, si vous voulez savoir quelle est la probabilité qu'il n'y ait que 2 pannes (parce que vous n'avez que deux ampoules), vous affectez la valeur 2 à la variable x.
Le code ci-dessus retournera la probabilité en appliquant la loi de Poisson.
Attention :
1 - il s'agit de la probabilité individuelle, pas de la probabilité cumulée. Si vous avez besoin de la proba cumulée, vous n'avez qu'à faire des boucles.
2 - le code ne fonctionne évidemment pas pour x = 0

Pour info, sous réserve d'erreur de frappe, ce code fonctionne depuis des années dans un logiciel de calcul de rechanges (entre autres). Vous pouvez donc y aller, c'est du bon !
Vos commentaires sont les bienvenus !

Pascal WOHMANN
otodidact Messages postés 2 Date d'inscription mercredi 29 novembre 2006 Statut Membre Dernière intervention 13 décembre 2006
13 déc. 2006 à 23:21
J'avoue, j'ai eu du mal à tout comprendre. Après une relecture encore plus concentrée, car plus intéressée, j'ai tout pigé (ou presque, je me penche sur l'ASM dès que possible).

Effectivement la validation des valeurs entrées est absente mais présente dans le code original... mais surement pas de cette manière !!! ;)... question de niveau.

Ensuite accéder aux registres, j'en ignorais la faisabilité en C... question de niveau aussi !!! :)

Merci à vous. Mais qui est TIGCC, AMANOBUO ?!

Sinon j'ai pour but de l'intégrer dans une beeeellle interface graphique avec wxDevCpp, mais n'importe quel sample fournit avec wxwidget ne compile pas. Donc,... Au secours !
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
13 déc. 2006 à 16:12
BruNews >> vu !
(De l'asm bien formé...)
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 déc. 2006 à 02:10
bien entendu il faut lire:
res = bnMult(128, 2987, &ovf);
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
13 déc. 2006 à 02:05
yann > pourquoi faire la multiplication 2 fois alors que c'est une opération couteuse en cycles ?
Tant qu'à le faire en asm, on y va complet et on gagne vraiment.
En __fastcall très rapide, 1 seul push, les 2 args vont en ecx et edx.
__declspec(naked) DWORD __fastcall bnMult(DWORD a, DWORD b, DWORD *pOvf)
{
__asm {
mov eax, edx
mul ecx
mov ecx, [esp+4]
mov [ecx], edx
ret 4
}
}

DWORD res, ovf;
res = (128, 2987, &ovf);
if(ovf) PASBON;
On gagne surtout la gestion d'erreur qui ruinerait toute performance.
pgassie Messages postés 12 Date d'inscription mardi 28 octobre 2003 Statut Membre Dernière intervention 13 décembre 2006
13 déc. 2006 à 00:15
Après reflexion, je présente ce petit code :


#include
#include<stdlib.h>
using namespace std;

const long FACT[]=
{1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600};

const unsigned long MAXULONG=-1; // idiot mais c'est l'astuce.
// "warning" mais compile !
const long MAXLONG = MAXULONG/2;

unsigned long multULong(unsigned long op1,unsigned long op2){
if (MAXULONG/op2<op1) cout <<"\t\a>>> PANIQUE <<<"<< endl;
return (op1*op2);
}

int main(int argc, char *argv[])
{
for (int i=0;i<13;i++)cout << i << "! = " << FACT[i] << endl;
cout << endl;

cout << "Max des unsigned long : " <<MAXULONG << endl;
cout << "Min des unsigned long : 0 (rappel)" << endl;
cout << "Max des long : " << MAXLONG <<endl;
cout << "Min des long : " << -MAXLONG-1 << endl;

cout << endl << endl;
cout << "OPERATIONS SURES" << endl << endl;
cout << "1250 x 3000 = " << multULong(1250,3000) << endl;
system("pause");
cout << "9999999 x 9999 = " << multULong(9999999,999) << endl;
system("pause");
return 0;
}

Explications :
1°) Une fonction fact() (massivement récursive) pour des valeurs d'entrée possibles de 0 à 12 (voir message précédent), c'est de la confiture à des cochons.
Bon sang, mais c'est bien sûr, un tableau de constantes suffit ! Et c'est plus rapide...
2°) Pour le calcul de MAXULONG, torturer un peu le compilateur est plus simple que de faire le calcul à partir de sizeof().
3°) Les dépassements de capacité ne peuvent se produire qu'avec l'addition et la multiplication.
La division entière MAXULONG par un op2 de 1 à MAXULONG a un résultat entier entre MAXULONG et 1. (Le cas zéro est zappé pour la clarté de cette démo).
Si MAXULONG/op2<op1 alors op2xop1<MAXULONG
Rest à faire : la simplification de n! / (k!(n-k)!).Une idée ?


Merci à yann_lo_san. Ta fonction n'est pas bête du tout, c'est à çà que je pensais...
si je ne me trompe pas, il doit même être possible de récupérer le produit qui est dans AX.
PS. Sous Konqueror, le textarea pour l'email fait deux lignes de vingt caractères, pour se relire c'est le pied.
Excusez les fautes de frappe.
Merci
Amanobuo Messages postés 65 Date d'inscription mardi 24 février 2004 Statut Membre Dernière intervention 11 décembre 2006
11 déc. 2006 à 23:16
As tu pense a le recompiler sous TIGCC ? ca pourrai etre tres utile !
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
11 déc. 2006 à 16:11
PGASSIE >> commentaire très instructif.
Voici un exemple bète pour gérer l'overflow des unsigned sur une multiplication (à adapter pour besoin)

unsigned short MultShortInt(unsigned short op1, unsigned short op2)
{
unsigned char ovf = 0x00;

__asm
{
mov ax, op1
mul op2
jc ERR
jmp FIN
ERR:
mov ovf, 01H
FIN:
}

if( ovf )
Throw(OVERFLOW_EXCEPTION);

return(op1 * op2);
}
pgassie Messages postés 12 Date d'inscription mardi 28 octobre 2003 Statut Membre Dernière intervention 13 décembre 2006
11 déc. 2006 à 07:13
Cher otodidacte,
Puisque tu sollicites des remarques, voici mes encouragements pour un code très propre, très proche de la formulation mathématique et quelques pistes pour l'améliorer.
1°)il n'y a aucun contrôle de validité, ni de dépassement de capacité, et des petits problèmes de type.
- si la fonction fact(int i)est attaquée par un négatif, la condition d'arrêt n'est jamais atteinte.
- tu prends la peine de retourner un long avec fact()mais ligne 65, tu la renvoies sur un pauvre int.(C'est pas très grave, voir ci-dessous)
- le MAXINT dépend du compilateur, avec le mien, la fonction fact(i)renvoie des valeurs correctes pour i de 0 à 12.
On est tenté de modifier les int et les long par "unsigned", toujours sur 32 bits, mais en ne prenant que les positifs on atteint 2^32-1, soit presque 4 300 000 000.
Malheureusement 13! est plus grand. Damned!
Alors, on ne touche à rien et on fait un test pour que i soit entre 0 et 12 et arrêt sinon.
L'autre solution, pas très élégante, est de transformer fact() pour qu'elle renvoie un double. Avec mon compilateur j'arrive à 171! (beaucoup).
Malheureusement (bis), avec les doubles, il est illusoire de croire qu'un nb x qui s'affiche 2.000 soit forcément égal à un nb y qui s'affiche aussi 2.000 .
Il faut alors définir un très petit epsilon (qui dépend de ta machine) et
remplacer le test x==y par x-y<=epsilon.
2°)Les fractions de factorielles.
-ce sont des entiers positifs, risquer des dépassements de capacités des erreurs d'arrondis en les transformant en rééls n'est pas terrible.
- les fractions d'entiers ne demandent qu'à être simplifiées. Comment ? C'est une bonne question, je vous remercie de me l'avoir posée.
Je crois voir deux listes d'entiers l'une pour ce qui se multiplie au numérateur, l'autre pour ce qui se multiplie au dénominateur, éliminer les entiers communs aux deux listes, diviser ce qui tombe juste, puis diviser les produits de ce qui reste dans les 2 listes.
Côté clarté du code, on n'a rien gagné mais la précision du résultat est meilleure.
3°)Le dépassement de capacité des entiers n'est à ma connaissance géré par aucun langage de haut niveau, alors que c'est tout bête en assembleur. Il y a un bit "overflow" qui reste à 0 si tout va bien.
Un truc consiste à vérifier que fac(i)>fac(i-1), si c'est faux, on est sûr qu'il y a dépassement.
Ici fact(13)>fact(12), hélas fact(13)<13xfact(12).
Si quelqu'un a une meilleure idée, c'est le moment.

Encore bravo otodidacte. Tu as remarqué que si je me suis acharné sur ta fonction fact, je n'ai rien dit sur les autres ; "double" a la bonne idée d'afficher "inf" pour infini.

Amitiés
otodidact Messages postés 2 Date d'inscription mercredi 29 novembre 2006 Statut Membre Dernière intervention 13 décembre 2006
30 nov. 2006 à 18:28
Merci Yann.

Ces lignes de codes représentent la synthèse de différents programmes sur des formules statistiques (bien qu'écrits en 2002) qui existaient déjà sur le site, et réécrits pour la Loi de Poisson. De manière un peu brouillonne pour les variables réutilisées, et sans passer par de multiples fonctions, afin d'éviter la gourmandise en ressources.

Bien que le résultat mathématique obtenu soit correct, le tableau de Poisson est destiné à des valeurs d'espérance E(x) beaucoup plus élevées. Mais il s'agit d'apprendre et de prendre plaisir.
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
29 nov. 2006 à 15:46
Et bien pour un autodidacte, ça vaut bien 9 !
Rejoignez-nous