Comment modéliser cette expérience en Scilab?

Bonjour, je souhaiterais savoir comment modéliser cette expérience par un programme Scilab svp ? Quel programme permettrait de simuler l'expérience décrite dans l'énoncé ?
Déjà personnellement je pense qu'il faut utiliser l'instruction "rand()" et par exemple, même si je sais que ce que j'ai fait n'est pas parfait et comporte des fautes forcément, voici ma piste.
z=0
c=0 / compteur
for k= 1 : n
c=c+1
if rand()<=(1/2)
    z=c
    end 
    disp(z)
else z=0
    end
end
disp(z)
Merci d'avance pour votre réponse.101122

Réponses

  • Heu ... Tu as fait tourner ton programme ? Il semble marcher ?
    Si tu ne l'as pas fait, il est inutile évidemment de demander ce qu'on en pense : Ce serait idiot de demander alors que tu peux savoir tout seul.

    Cordialement.
  • Non, même sans le faire tourner je sais qu'il ne marchera pas par intuition, car ce qui me pose problème dans ce programme, c'est comment modéliser en Scilab le fait que la valeur de Z ne change plus après avoir pris la valeur du numéro du tirage où l'on a obtenu "pile" pour la première fois (en admettant que "pile" est obtenu au moins une fois). Car le problème c'est que ça ça ressemble à une boucle "while", mais le problème est qu'ici je ne peux pas utiliser une boucle "while" car cette dernière sous-entend un nombre infini de répétitions de l'expérience jusqu'à ce qu'on obtienne le premier succès (ici "obtenir un pile"), or ici dans cet expérience on effectue pas un nombre infini de lancers de la pièce, on en effectue un nombre fini n, ce qui correspond à une boucle "for". Voilà pourquoi je suis bloqué. Vous voyez ce que je veux dire ?
  • Il suffit de mettre un compteur qui arrête la boucle while quand on a fait n lancers.
  • On peut utiliser une boucle "for" avec une sortie exceptionnelle de boucle (si ça existe en scilab), ou en forcer une en modifiant dans la boucle la valeur de l'index de boucle (si "condition alors z=c et k = n+1) ou bien faire la même chose avec un while.

    Enfin, la programmation avec des boucles n'est pas le fonctionnement de base de Matlab et Scilab, langages matriciels, il est préférable de faire un vecteur de booléens rand()<0.5 et de faire chercher le rang du premier "true".
    J'ai abandonné scilab depuis trop longtemps pour dire comment faire.

    Cordialement.
  • Gérard a écrit:
    il est préférable de faire un vecteur de booléens rand()<0.5 et de faire chercher le rang du premier "true".

    Non, pas ici.
    Les facilités d'un langage ne devraient intervenir que dans l'implémentation de l'algorithme, pas dans le choix de l'algorithme.
    Ici, si on tire le tableau à l'avance, ce sera vraisemblablement pour rien (on simule une loi géométrique tronquée, ou presque).
  • Oui exactement, si $n=10^8$ et qu'on fait pile au premier tirage, c'est un peu bête d'avoir simulé autant de lancers...
  • Une solution en Julia.
    function simulation(N)
        u=rand()
        i=1
        while (u<1/2) && (i<N)
            i+=1
            u=rand()
        end
        if (u<1/2) return(0)
        else
            return(i)
        end
    end
    
    L'adapter en Scilab ne devrait pas être trop difficile.

    PS: je regrette le "repeat until" de Turbo Pascal. Je ne comprends pas que la plupart des langages aient choisi de s'en passer. On peut toujours l'émuler avec des "exit" mais ce n'est pas cool.
  • Ah, effectivement ! ici, il est très probable d'avoir rapidement un pile, même pour n assez faible.
    Ce serait différent si les probas étaient très déséquilibrées, scilab étant optimisé pour le travail matriciel.

    Cordialement.
  • Je ne sais pas trop ce qui serait attendu vu que le sujet date de l'époque Turbo Pascal qui ne connaissait que random.
    La solution avec boucle et compteur est très bien et sera proposée par le plus grand nombre de candidats (du moins pour ceux qui veulent bien se donner la peine d'y répondre).
    Sinon, en exploitant les possibilités de Scilab :
    n=10 ; X=grand(1,n,"bin",1,0.5) ; disp(X)
    Z=max([0,min(find(X==1))]) ; disp(Z)
    mais je n'imagine pas un candidat en ECS/ECE proposer cette solution.
  • Effectivement, Guiguiche,

    tu utilises l'aspect matriciel. Est-ce vraiment plus long si n = 1000 par exemple (le cas Z=0 est très improbable) ?

    Cordialement.
  • Ce que j'avais remarqué avec les étudiants, c'est l'incroyable différence de temps de calcul sur la somme partielle de la série harmonique selon que l'on utilise :

    n=10^6 ; S=sum(1 ./[1:n]) // ultra rapide

    ou bien :

    n=10^6 ; S=0 ; for k=1:n S=S+1/k ; end // plusieurs minutes sur la même machine

    Pour les simulations d'estimation, je tente de faire utiliser au maximum les possibilités matricielles de Scilab aux étudiants mais ils y semblent très réfractaires (de manière générale, la programmation est un problème pour la plupart d'entre eux). L'inconvénient de l'aspect matriciel est la taille limitée des matrices que l'on peut utiliser.
  • Oui,

    si je me souviens bien, Scilab est un langage interprété, donc dans le deuxième cas, c'est l'interpréteur qui fait un million de boucles, alors que le calcul matriciel est en langage compilé, bien plus rapide.
    Si j'ai un moment, je réinstallerai scilab sur ma machine.

    Cordialement.
  • ce que décrit Guiguiche c'est le recours à ce qu'on appelle la "vectorisation" et qui fait appel à des librairies pré-compilées (et donc beaucoup plus rapides); cet outil n'est pas propre à Scilab, puisqu'il est également disponible sous Matlab ou Numpy/Python par exemple; sur ce dernier langage, j'ai déjà mesuré des ratios supérieurs à 100 sur des calculs (voir un post dédié)
  • guiguiche a écrit:
    mais je n'imagine pas un candidat en ECS/ECE proposer cette solution.

    Je peux vous assurer que de tels candidats existent... (mais sont très rares, je vous l'accorde).
  • Bonjour

    Deux codes Scilab des plus basiques pour illustrer mon dernier post; les calculs sont de l'ordre de 60 à 100 fois plus rapides en utilisant la vectorisation pour un vecteur de 1 million de lignes.

    On fera attention au " .^ "
    mode(0);
    
    n = 1E6;
    x = [1 : n]'; // creation du vecteur
    
    // avec boucle (temps de référence)
    x0 = zeros(n); // initialisation obligatoire pour éviter l'allocation dynamique
    tic();
    for i = 1 : n
        x0(i)=x(i)^2;
    end
    temps0 = toc();
    printf("Le temps de référence est de %g\n\n",temps0);
    
    
    // façon 1: initialisation n'est pas nécessaire puisqu'elle s'appuie sur le vecteur x
    tic();
    x1 = x.^2;
    temps1 = toc();
    printf("Façon 1, le temps est de %g\n",temps1);
    printf("le ratio est de %g\n\n",temps0 / temps1);
    
    // façon 2: "slicing" à la mode Scilab
    tic()
    x2 = x([1:n],:)^2;
    temps2 = toc();
    printf("Façon 2, le temps est de %g\n",temps2);
    printf("le ratio est de %g\n\n",temps0 / temps2);
    
    

    on regardera " ./ " et " .* "
    mode(0);
    
    n = 1E6;
    V1 = rand(n,2);
    V2 = rand(n,2) ./ rand(n);
    
    // avec des boucles
    tic();
    Scal_1 = zeros(n);
    for i = 1 : n
        Scal_1(i) = V1(i,1)*V2(i,1) + V1(i,2)*V2(i,2);
    end
    temps0 = toc();
    printf("Le temps de référence est de %g\n\n",temps0);
    
    
    // par vectorisation
    tic();
    Scal_2 = V1(:,1) .* V2(:,1) + V1(:,2) .* V2(:,2);
    temps1 = toc();
    printf("le temps est de %g\n",temps1);
    printf("le ratio est de %g\n\n",temps0 / temps1);
    
    // vérification
    difference = max(abs(Scal_1 - Scal_2));
    if (difference == 0.) then
        printf("Aucune différence entre Scal_1 et Scal_2");
    else
        printf("Différence(s)trouvée(s)");
    end
    

    Paul
  • Effectivement,

    mais dans le cas de l'exercice du premier message, même avec n de l'ordre du million, on ne fera pas des centaines de boucles. Il y a déjà moins d'une chance sur 1000 qu'on ait besoin de plus de 10 boucles.

    Cordialement
  • je me suis écarté du sujet d'origine, je reconnais ;-)
  • Merci beaucoup à tous pour vos remarques. Je pense toutefois que c'est en effet la solution d'Aléa qui me parle le plus et qui s’approcherait le plus du programme que j'aurais proposé si l'on me posait cet exercice. En Scilab je pense que ça donne :
    u=rand()
        i=1 / compteur
        while (u<1/2) & (i<N)
            i=i+1
            u=rand()
        end
        if (u<1/2) disp(0)
        else
            disp(i)
        end
    end
    
    Merci encore :-)
  • On peut utiliser un break qui arrête la boucle au premier pile, ce qui donne un code très simple :
    z = 0
    for i = 1:n
      if rand() < 0.5 then
        z = i
        break
      end
    end
    disp(z)
    
Connectez-vous ou Inscrivez-vous pour répondre.