Forth : La méthode de Monte-Carlo

Cette catégorie traite de développements récents destinés à nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Papy.G, fneck, Carl

Avatar de l’utilisateur
Dominique
Messages : 829
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Forth : La méthode de Monte-Carlo

Message par Dominique »

MonteCarlo.gif
MonteCarlo.gif (223.55 Kio) Consulté 5561 fois
Je ne suis pas certain d’avoir tout bien compris des travaux de l’ami lost level dans le sujet du bac à sable « L'oséotis d'Arthémus » mais comme kweeky en avait parlé ici
http://forum.system-cfg.com/viewtopic.p ... 27#p116811
je me suis décidé à tester la méthode de Monte-Carlo sur le MO5 et en Forth bien entendu.
Analysant le jet d’une pièce sur un carrelage, Buffon disait dans son « Essai d’Arithmétique morale » en 1778 « le sort du premier joueur fera à celui du second, comme la superficie de la couronne circonscrite est à la superficie de la figure inscrite; cela peut se démontrer aisément… »
C’est clair et limpide !
Soit un carré de coté 200, un quart de cercle de rayon 200 ayant pour origine l’un des sommets, un point de coordonnées X Y – X Y compris entre 0 et 200 -, la probabilité de ce point de se trouver à l’intérieur du ¼ de cercle « est comme la superficie de l’un est à la superficie de l’autre »
Même si elle est moins glamour, l’avantage de la méthode de Monte-Carlo est qu’elle ne peut pas être suspectée de triche : PI apparait miraculeusement à partir de la formule de Pythagore qui vérifie si le point est à l’intérieur ou à l’extérieur du cercle. Alors que la simulation informatique de l’aiguille de Buffon fait généralement intervenir des radians et de la trigonométrie que l’on peut accuser de cacher PI.
Malheureusement le langage Forth n’est pas le plus adapté pour ce genre de calculs (avec les décimales en plus). Mais on peut quand même s’amuser un peu.

Wikipedia nous donne les clefs pour la mettre en œuvre.
Comme le Forth travaille avec des entiers l’approximation de PI sera donnée de la façon suivante
PI(approximé)= 10000 * 4 * Nombre de points dans le ¼ de cercle/ nombre d’essais.
Ce programme n’est qu’une ébauche pour 32000 essais mais on pourrait aller plus loin :
- DO … LOOP nous limite à des entiers signés < 32767 on pourrait prévoir un test sur des entiers non signés ramenant à 65536
- La fonction RANDOM est elle vraiment aléatoire ?
- Il y a quelque part une accumulation de données (peut être un reste de division …) mais comme je n’ai pas le temps de faire un debug, j’ai opté pour la solution des paresseux : la remise à plat de la pile SP à chaque LOOP par SP! si quelqu’un le trouve merci de le signaler.
- Les couples X Y dont X2+Y2=R2 sont considérés rouges, donc inclus … Doivent-ils l’être ?

Code : Tout sélectionner

( Début programme)
: TASK ; 

( Mode décimal)
DECIMAL 

( a b c d . . . c  d a b )
: 2SWAP ROT >R ROT R> ; 

(a b . . . a b a b)
: DDUP OVER OVER ;

(dun . . . ) (imprime double unsigned : 32 bits non signés)
: DU. SWAP OVER <# #S #> TYPE DROP ; 

( d1  n . . . t=d1*n ) (double*simple = triple)
: T* DUP ROT U* >R >R U* 0 R> R> D+ ; 

(t  n . . . d1= t/n) (Triple/simple=double)
: T/ >R I U/ SWAP ROT 0 I U/ SWAP ROT R> U/ SWAP DROP 0 2SWAP SWAP D+ ; 

(ici RND initial = valeur de la variable système HERE – On peut changer par n’importe quelle valeur) 
0 VARIABLE RND     HERE      RND ! 

(constante double)
: DCONSTANT <BUILDS SWAP , , DOES> DUP @ SWAP 2+ @ ; 

( a b . . . b)
: NIP SWAP DROP ; 

(Formule aléatoire)
: RANDOM RND @ 31421 * 6927 + DUP RND ! ;

(N . . .  0<Aléatoire<N)
 : CHOOSE RANDOM U* NIP ;

(Coordonnées du point)
0 VARIABLE XA 
0 VARIABLE YA 

(Nombre de points rouges dans le ¼ de cercle)
0 VARIABLE ROUGE 

(création de constantes pour gain de temps durant l’exécution)
(Constante simple)
20000 CONSTANT 20K    
(Constantes doubles) 
40000. DCONSTANT 40K    
400000000. DCONSTANT 400M 

 (100X  100Y . . . ) (Impression du point X/100 Y/100)
: PLOT INKG >R 100 / R> 100 / PSET ;      

 (dX  dY . . . dX2+dY2)  (Pythagore)                                   
: DIAGONALE DUP U* ROT DUP U* D+ ; 

(. . . . .) (Génère un couple, calcule le carré de sa distance par DIAGONALE compare avec 400M et met à jour ROUGE si 
             le point est à l’intérieur)
: ESSAI 20K CHOOSE 20K CHOOSE DDUP DIAGONALE DMINUS 400M D+  0<  SWAP DROP 0= IF  1 ROUGE +! 5 PLOT ENDIF ; 

(Nbre essais . . .)  ( 40000 * Nbre de rouges / nombre d’essais)
: PRINTPI >R 40K ROUGE @ DUP 9 27 LOCATE . T* R> T/  17 28 LOCATE DU. ; 

(Génération de Random)
: GENALEAT CLS   4   9  LOCATE ." LA METHODE DE MONTE-CARLO"  6  5 LOCATE ." DETERMINATION DE LA VALEUR DE PI" 20  15 LOCATE 
    ." DOMINIQUE CONTANT 2016"  11  5  LOCATE ." GENERATION DES VALEURS ALEATOIRES" 100 0 DO LOOP 14  9  LOCATE 
    ." LAISSER UN CERTAIN TEMPS"  15  5  LOCATE ." PUIS APPUYER SUR LA BARRE ESPACE" BEGIN 1 RND +! KEYF 25 =   UNTIL ; 

(. . . . ) (écran principal)
: PRESENTATION GENALEAT CLS 5 INKG 201 0 319 199 BOX  1  26 LOCATE ." PI:METHODE DE"    2  27 LOCATE ." MONTE CARLO"  
  4  27 LOCATE ." ===========" 8  26 LOCATE ." POINTS RGES:"  11  26 LOCATE ." ESSAIS:" 14  27 LOCATE ." ===========" 
  16  26 LOCATE ." VALEUR DE PI:"  21  28 LOCATE ."30/04/2016"  ; 

( . . . ) (Barre d’espace pour arrêt)
: TOUCHE KEYF 25 = IF BEGIN KEYF 25 = 0= UNTIL KEY DROP ENDIF ; 

(Lancement du programme)
: MONTE-CARLO PRESENTATION    10000 1 DO ESSAI I DUP 12  27 LOCATE . PRINTPI TOUCHE SP! LOOP ;
Chargement.jpg
Chargement.jpg (13.56 Kio) Consulté 5561 fois
K7 :
Monte Carlo.zip
(2.88 Kio) Téléchargé 146 fois
Lire le fichier README pour lancer le programme :
Edit : Correction fichier vide
Dernière modification par Dominique le 30 avr. 2016 23:34, modifié 1 fois.
__sam__
Messages : 7965
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Forth : La méthode de Monte-Carlo

Message par __sam__ »

Joli :)
La fonction RANDOM est-elle vraiment aléatoire
En fait non. :( Je pense que c'est un générateur "modulo-congruentiel". Cela se voit par l'apparition d'alignements diagonaux quand il y a pas mal de points affichés. Les générateurs "modulo-congruentiels" sont simples et rapides. C'est pourquoi ils étaient pas mal employés dans les langages des années 80. Hélas, en pratique, ils sont assez mauvais à cause de ces alignements qui apparaissent quand on affiche des points au hasard dans une grille 2D. En outre comme tu affiches 32000 points, et que le génétateur a probablement un état interne sur 16bits, il est quasi certain que tu retombes plusieurs fois sur la même séquence de points empêchant de remplir totalement le disk pour avoir la meilleur approximation (problème de cycle court des générateurs modulo-congruentiels).

Il faurait utiliser un générateur rapide tout ayant un nombre de bits interne plus grand (2x par exemple) que le nombre de points que tu veux tirer. Un bon exemple ayant un état interne sur 32bits est celui présenté ici: http://www.excamera.com/sphinx/article-xorshift.html.

Ah oui, j'oubliais: le lien contient une implémentation forth 32 bits :D Une implementation pour forths 16bits ne doit pas être trop compliquée dans la mesure où le générateur ne fait que des décalages à gauche ou a droite et des xor bits à bits facilement adaptable sur des paires adjacentes de cellules 16bits.

[EDIT] Je viens de lire le code FORTH que tu as posté et je confirme, c'est bien un générateur "modulo-congruentiel"

Code : Tout sélectionner

(Formule aléatoire)
: RANDOM RND @ 31421 * 6927 + DUP RND ! ;
Ils sont très mauvais du point de vu statistique. Ainsi par exemple, on peut prédire très facilement le bit de poids faible du prochain tirage. En effet, le bit de poids faible de ce générateur alterne successivement entre 0 et 1. Du coup je me suis toujours demandé si les gens qui produisent un bit aléatoire en utilisant uniquement le bit de poids faible d'un tel générateur (opération logique "and 1") comprenaient vraiment ce qu'ils faisaient. Ce bit là n'est pas du tout aléatoire. Le bit suivant ne l'est pas tellement plus dans la mesure où sa valeur ne dépend exclusivement de celle qu'il avait au tirage précédent combiné à celui du bit de poids faible (que l'on sait parfaitement déterminer). Si j'ai bonne mémoire le bit 2 a une période d'au plus 4 tirages. Donc au bout de 4 tirages on peut prédire quel sera la prochaine valeur :mrgreen:

Bref ces générateurs sont à oublier si on veut faire des statistiques fiables (surtout si on utilise les bits de poids faible extraits par modulo ou masque logique).
Dernière modification par __sam__ le 30 avr. 2016 23:19, modifié 1 fois.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17412
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Forth : La méthode de Monte-Carlo

Message par Daniel »

Je crois que la cassette pi_monte-carloV1.k7 (dans l'archive Monte Carlo.zip) est vide.

Dans les années 1980 j'avais aussi essayé la méthode de Monte Carlo sur MO5 pour calculer PI (mais pas en Fortran). Il me semble qu'elle est très longue à converger, et je l'avais vite abandonnée au profit de développements limités.

En nombre réels le point au hasard a une probabilité nulle de tomber juste sur le cercle. En nombres entiers ça peut arriver, intuitivement je crois qu'on peut ignorer ce point et faire un nouveau tirage.
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
Dominique
Messages : 829
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Forth : La méthode de Monte-Carlo

Message par Dominique »

OK Sam

Forth Dimensions V08N03 page 31 donne une solution FIG FORTH que je n'avais pas voulu mettre de peur que ça ralentisse trop.
Je vais la mettre dans une nouvelle version.
Avatar de l’utilisateur
Dominique
Messages : 829
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Forth : La méthode de Monte-Carlo

Message par Dominique »

Mauvaise manip ! Excuses. Je vais la remettre


Edit : Fichier avec bug retiré
Dernière modification par Dominique le 01 mai 2016 17:34, modifié 1 fois.
__sam__
Messages : 7965
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Forth : La méthode de Monte-Carlo

Message par __sam__ »

Mince, le pdf que je récupère de http://www.forth.org/fd/FD-V08N3.pdf ne contient que des pages blanches :( du coup je ne sais pas quel est le générateur qui y est défini. S'il a un état interne sur 32 ou 48 bits c'est bien mieux que les 16bits de celui que tu avait initialement utilisé.

Je pense à un truc tout bête: puisqu'on a un carré 200x200, on peur carément compter tous les points (entiers) (X,Y) tels que X*X+Y*Y<200*200. Ca ne dépend pas du générateur aléatoire et c'est tout simple à faire (en basic par exemple):

Code : Tout sélectionner

10 R=200
20 N=0
30 FOR X=0 TO R-1
40   FOR Y=0 TO R-1
50      IF X*X+Y*Y<R*R THEN N=N+1
60   NEXT
70   ? INT((100*X)/R);"%        ";CHR$(13);
80 NEXT
90 ? "Approx:"; 4*N/(R*R)
Ca donne N=31602, donc une approximation de 3.16. Pas terrible. :?

Avec un carré de 1000x1000 (définir R=1000 en ligne 20), on obtient 3.1455 c'est mieux, mais ca converge très très lentement.

Code : Tout sélectionner

10 R=10
90 ? "R =";R;"Approx:";4*N/(R*R)
100 R=R*2
110 GOTO 20
Dernière modification par __sam__ le 30 avr. 2016 23:59, modifié 2 fois.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
Dominique
Messages : 829
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Forth : La méthode de Monte-Carlo

Message par Dominique »

Si tu ne le trouves pas vite :
Forth Random.jpg
Forth Random.jpg (256.01 Kio) Consulté 5547 fois
__sam__
Messages : 7965
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Forth : La méthode de Monte-Carlo

Message par __sam__ »

Merci :D

J'ai un peu de mal à suivre la logique de l'usage du tableau, mais si ne me trompe pas on se base encore sur la fonction "RANDOM". Du coup on souffre encore d'une périodicité d'environ 32000 a moins que le tableau intervienne dans l'état interne du générateur. Il faut que je comprennet la logique du remplacement qui est mis en oeuvre. Ca fait un peu penser à https://fr.wikipedia.org/wiki/M%C3%A9la ... sher-Yates, mais ce n'est pas exactement la même chose puisqu'on échange pas les nombres, mais on insère un autre nombre aléatoire dans le tableau à chaque fois.

Hum ok.. je crois que le tableau sert à casser les régularités du RANDOM, mais en fait je suis persuadé qu'on a quand même au plus un cycle de 32000 et quelques nombre différents. Au bout de 32000 et quelques on revient à nouveau en début de cycle.

Je crois que le l'algo par décalage + xor est à la fois plus rapide et meilleur (32bits d'état interne).
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
Dominique
Messages : 829
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Forth : La méthode de Monte-Carlo

Message par Dominique »

@Sam
Pour ce qui est de ton observation en prenant tous les points également répartis, je comprend ce que tu veux dire, mais en fait tu reproduit la réflexion de Buffon sur la probabilité = la raison des surfaces en remplaçant les superficies pas une notion équivalente de densité.

Sauf qu'on fuit de la raison principale qui est de prouver par l'expérience que l'intuition de Buffon était bonne. Et on sait qu'elle l'était.

Demain j'essaye de mettre les modifications de Forth Dimensions.

Je suis d'accord avec vous deux : cette méthode converge lentement et ce n'est pas avec le peu de lancements simulés qu'on arrivera a un résultat probant. D'ailleurs dans mes tests je me suis surpris à croiser les doigts pour que la valeur baisse quand je la voyais tourner aux alentours de 3,1800 ! :D
__sam__
Messages : 7965
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Forth : La méthode de Monte-Carlo

Message par __sam__ »

Oui.. Attention toutefois avec le tirage aléatoire. Il impacte directement la qualité du résultat. En principe il faudrait tirer les réels totalement au hasard avec un précision infinie. Mais comme les rééls machine sont finis, on est restreint à tirer au hasard un nombre de bit assez faible. Typiquement il faut tirer au hasard chacun des 23bits de la mantisse pour les floats 32bits ou des 53bits pour les doubles 64bits (IEE754).

Or quand on tire un nombre entre 0 et 1 en faisant random()/65536.0 (random retournant un entier non signé sur 16bit), on n'introduit pas 23 ou 53 bits d'entropie dans le réel, mais seulement 16bits: des bits parmi les 23 ou 53 sont fortement correllés et certains motifs n'apparaissent jammais dans la mantisse. Au final, parmi les 2^53 doubles possibles dans [0, 1[, on en tire jammais plus de 65536, soit 3.6E-10 %. C'est très faible.

Du coup il y a un méchant biais dans le tirage au sort des réels qui retombent assez souvent sur les mêmes valeurs. Cela impact négativement la précision de la méthode. Avec une mantisse sur 53bits c'est à dire avec un générateur ayant minium 53bits d'état, on pourrait calculer pi à 2^-53 près (15 chiffres exacts), mais avec un générateur à 16bits d'états, on approxime pi à 2^-16 près soit au mieux avec 4 chiffres après la virgule. Avec un générateur sur 32bits, on doit pouvoir avoisiner les 8 chiffres après la virgule au bout d'un temps très très long.

Un temps long? oui. Si j'ai bonne mémoire les méthodes type monté-carlo convergent en constante/sqrt(N) (N=nombre d'échantillons) vers la moyenne. Donc pour atteindre 4 chiffres après la virgule, il faut faire pas loin de 1E8 tirages Sur nos 8bits, c'est une éternité! :mrgreen:
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
Dominique
Messages : 829
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Forth : La méthode de Monte-Carlo

Message par Dominique »

Si j'ai bien compris :
- 32 bits est un étage du stack du 32-bit ANS Forth au lieu d'un étage de 16 bits sur le Forth du MO5

http://www.excamera.com/sphinx/article-xorshift.html

S'il est donc dit 7 DUP ( en ANS 32 bits ) cela correspond à 7. DDUP du FIG du MO5.
Donc re écrire tous les DUP @ OR XOR et autres 0= en DUP D@ DOR DXOR D0= etc..

- Ensuite je ne vois pas comment faire pour générer ces Random à l'intérieur d'un intervalle |0 - 200|
Xavier

Re: Forth : La méthode de Monte-Carlo

Message par Xavier »

Salut les Fortheurs (sans les vagues) !
- Ensuite je ne vois pas comment faire pour générer ces Random à l'intérieur d'un intervalle |0 - 200|
En basic:
10 FOR I=0 TO 200:IF INKEY$<>"" THEN NEXT:GOTO 10
20 PRINT "Le nombre aléatoire est :";I:GOTO 10

... Bon, ça fait mal au doigt passé les 32000 premiers nombres... :lol:

Juste une question, Daniel a évoqué le "Fortran", ce langage est donc un cousin du Forth ?

Nota:
Vu la dispersion des plombs, ce doit être la méthode "Marseillaise" et non "Monte-Carlo" !
Avatar de l’utilisateur
Dominique
Messages : 829
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Forth : La méthode de Monte-Carlo

Message par Dominique »

Salut Xavier !

En y réfléchissant je pense que c est comme avec les 16 bits mais avec les 32 :D

Code : Tout sélectionner

(N . . .  0<Aléatoire<N)
: CHOOSE RANDOM U* NIP ;
Deviendra

Code : Tout sélectionner

: CHOOSE RANDOM D* NIP ;
où D* multiplie 2 doubles restituant 1 double ce qui est gênant parce que 2147483647 * 200 ne tient pas dans un 32 bits ... :?:
Xavier

Re: Forth : La méthode de Monte-Carlo

Message par Xavier »

Salut Dominique!

A la lumière de ce que _SAM_ nous a proposé, seul de quartet de point faible à le plus de chance d'être aléatoire...
Donc, sur 16bits, tu prends les quartets 2 et 4 pour te donner un 8 bits avec un AND pour avoir 200 :?:
... vu qu'en 32bits, il y aura forcement de l'arrondi à la hache...
__sam__
Messages : 7965
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Forth : La méthode de Monte-Carlo

Message par __sam__ »

Dominique a écrit :Si j'ai bien compris :
- 32 bits est un étage du stack du 32-bit ANS Forth au lieu d'un étage de 16 bits sur le Forth du MO5
oui.
Donc re écrire tous les DUP @ OR XOR et autres 0= en DUP D@ DOR DXOR D0= etc..
Tout à fait. Tout est à traiter par paquet de 2 cellules de pile. Le plus compliqué sont probablement les décalages. Mais décaler à droite de 17 revient à ne prendre que la partie haute et décaler à droite une fois ("DROP 0 SWAP D2/" si je ne me plante pas). Pour le décalage à gauche de 13 il faut multiplier les parties hautes et basses par 8192 et faire une addition 32bits. Ca doit donner un truc genre "8192 UM* ROT 8192 UM* SWAP DROP 0 D+".
- Ensuite je ne vois pas comment faire pour générer ces Random à l'intérieur d'un intervalle |0 - 200|
L'idéale serait d'avoir des doubles flottants, mais je crois qu'ils n'existent pas sur le forth MO5. Sinon, il faut le diviser par 65556 (c-à-dire: on ne prend que le poids fort 16bits), multiplier par 200 (résultat sur 16bits) et ne prendre à nouveau que les 16 bits de poids fort ==> DROP 200 UM* DROP (toujours si je ne me plante pas). A noter: tu pourrais facilement travailler avec un carré plus grand que 200 (10000 par ex) avec les opérations 32bits car 10000x10000 reste largement dans la fourchette des 32bits. Bon, la contrepartie est que ce sera plus lent.

@Xavier: non le Fortran n'est pas cousin du Forth. Le fortran n'est pas à langage à pile. Sa structure de donnée privilégiée est le tableau. Il est plutot fait pour faire de gros calculs lourds sur les nombres stockés dans des tableaux (typiquement matrices, algèbre linéaire, optimisation de fonctions, etc). Il est, pour moi, à vocation des scientifique plutôt que du tout venant. D'ailleurs le mot fortran signifie: FORmula TRANslation, on voit bien qu'ils s'addresse à ceux qui utilisent des formules :wink:
Dernière modification par __sam__ le 01 mai 2016 12:38, modifié 1 fois.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Répondre