<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Philben - Ms Access &#187; Aléatoire</title>
	<atom:link href="https://blog.developpez.com/philben/ptag/aleatoire/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/philben</link>
	<description></description>
	<lastBuildDate>Thu, 26 Sep 2013 19:43:53 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Un meilleur RNG&#8230;</title>
		<link>https://blog.developpez.com/philben/p10822/vba-access/un_meilleur_rng</link>
		<comments>https://blog.developpez.com/philben/p10822/vba-access/un_meilleur_rng#comments</comments>
		<pubDate>Sun, 11 Mar 2012 21:47:59 +0000</pubDate>
		<dc:creator><![CDATA[philben]]></dc:creator>
				<category><![CDATA[VBA - Ms Access]]></category>
		<category><![CDATA[Aléatoire]]></category>
		<category><![CDATA[Algorithme]]></category>
		<category><![CDATA[Code VBA]]></category>
		<category><![CDATA[Numérique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[En parcourant le web, j&#8217;ai lu de nombreuses critiques concernant les générateurs de nombres aléatoires livrés avec les systèmes d&#8217;exploitation, les langages de programmation&#8230; Et notre couple Randomize/Rnd que vaut-il ? Tester un RNG (Random Number Generator) nécessite de lui &#8230; <a href="https://blog.developpez.com/philben/p10822/vba-access/un_meilleur_rng">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>En parcourant le web, j&rsquo;ai lu de nombreuses critiques concernant les générateurs de nombres aléatoires livrés avec les systèmes d&rsquo;exploitation, les langages de programmation&#8230;</p>
<p><strong>Et notre couple Randomize/Rnd que vaut-il ?</strong><br />
<span id="more-2"></span><br />
Tester un RNG (Random Number Generator) nécessite de lui faire passer une batterie de tests statistiques qui permettent de mesurer leur qualité.<br />
le plus célèbre jeu de tests est <em><a href="http://en.wikipedia.org/wiki/Diehard_tests">DieHards tests</a></em> de G. Marsaglia mais je me suis amusé à tester notre générateur avec le programme de <a href="http://www.fourmilab.ch/random/">fourmilab</a> (explications sur les résultats).</p>
<p><strong>Résultats</strong></p>
<blockquote><p>
Entropy = 6.960137 bits per byte.</p>
<p>Optimum compression would reduce the size<br />
of this 11469916 byte file by 12 percent.</p>
<p>Chi square distribution for 11469916 samples is 91767249.86, and randomly<br />
would exceed this value less than 0.01 percent of the times.</p>
<p>Arithmetic mean value of data bytes is 111.6449 (127.5 = random).<br />
Monte Carlo value for Pi is 3.304316894 (error 5.18 percent).<br />
Serial correlation coefficient is -0.036392 (totally uncorrelated = 0.0).
</p></blockquote>
<p>Les résultats démontrent que notre RNG n&rsquo;est pas à la hauteur de nos espérances&#8230;</p>
<p>Si vous avez besoin d&rsquo;un bon générateur de nombres aléatoires, vous avez deux possibilités :</p>
<p><strong>Récupérer un code VBA existant sur le web</strong><br />
Depuis la fin des années 90, il existe d&rsquo;excellents algorithmes qui utilisent nativement des variables &lsquo;unsigned long&rsquo; voir des &lsquo;unsigned long long&rsquo; ce qui ne facilite pas le portage en VBA avec notre type &lsquo;long&rsquo;&#8230;</p>
<p>J&rsquo;ai quand même péché sur le web deux RNG de qualité.</p>
<ul>
<li>Le fameux &lsquo;Mersenne twister&rsquo; porté <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/BASIC/mt19937arVBcode.txt">ici</a> en VBA.</li>
<li>et <a href="http://burtleburtle.net/bob/rand/isaacafa.html">ISAAC</a> de qualité cryptographique</li>
</ul>
<p>Ces deux RNG codés en VBA passent sans problème les tests qualité de Fourmilab.</p>
<p>Exemple avec ISAAC :</p>
<blockquote><p>
Entropy = 7.999985 bits per byte.</p>
<p>Optimum compression would reduce the size<br />
of this 11469916 byte file by 0 percent.</p>
<p>Chi square distribution for 11469916 samples is 236.35, and randomly<br />
would exceed this value 79.31 percent of the times.</p>
<p>Arithmetic mean value of data bytes is 127.4950 (127.5 = random).<br />
Monte Carlo value for Pi is 3.141571792 (error 0.00 percent).<br />
Serial correlation coefficient is -0.000191 (totally uncorrelated = 0.0).
</p></blockquote>
<p><strong>En adapter un&#8230;</strong><br />
Je dis bien &lsquo;adapter&rsquo; et non &lsquo;programmer&rsquo; car se sont des algorithmes très pointus.<br />
Je me suis d&rsquo;abord penché sur des sources qui utilisaient des variables &lsquo;uint32&prime; dans le but de simplifier l&rsquo;adaptation.<br />
Leur qualité dépassait rarement celle de notre Rnd et j&rsquo;ai du me résoudre à explorer les sources &lsquo;modernes&rsquo; qui exploitent les &lsquo;uint64&prime;.<br />
Je me suis intéressé à la <a href="http://school.anhb.uwa.edu.au/personalpages/kwessen/shared/Marsaglia03.html">méthode MWC</a> &lsquo;Multiply with carry&rsquo; de G. Marsaglia tout particulièrement à l&rsquo;algorithme MWC256.</p>
<p>Voici donc mon adaptation de son code :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:400px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #008000;">'Random number generator - MWC256 - Multiply with Carry<br />
</span><span style="color: #008000;">'Author : George Marsaglia<br />
</span><span style="color: #008000;">' Reference : http://school.anhb.uwa.edu.au/personalpages/kwessen/shared/Marsaglia03.html<br />
</span><span style="color: #008000;">' Period about 2^8222. Uses a static array Q[256] and an initial carry 'c',<br />
</span><span style="color: #008000;">' the Q array filled with 256 random 32-bit integers in the calling program<br />
</span><span style="color: #008000;">' and an initial carry c&lt;809430660 for the multiply-with-carry operation<br />
</span><span style="color: #008000;">'Adapted from C to VBA : Philben - v1.0 - 03/2012<br />
</span><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> MWC256_UINT32(<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> Start <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span> = <span style="color: #00C2FF; font-weight: bold;">False</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span><br />
&nbsp; &nbsp;Const ULL <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 2 ^ 64<br />
&nbsp; &nbsp;Const UL <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 2 ^ 32<br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Static</span> Q(1 <span style="color: #8D38C9; font-weight: bold;">To</span> 256) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Variant</span>, c <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Variant</span>, a <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Variant</span>, i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> t <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Variant</span>, v <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Variant</span><br />
<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> Start <span style="color: #8D38C9; font-weight: bold;">Or</span> i = 0 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; Randomize<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">'c &lt; 809430660 - 0 &lt;= Rnd &lt; 1 - Marsaglia : c=362436<br />
</span> &nbsp; &nbsp; &nbsp;c = CDec(CLng((809430660 - 2 ^ 12) * Rnd() + 2 ^ 11))<br />
&nbsp; &nbsp; &nbsp; a = CDec(809430660)<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> 256<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Q(i) = CLng(Rnd() * (2 ^ 31 - 1))<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">'warm up<br />
</span> &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MWC256_UINT32<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Loop</span> <span style="color: #8D38C9; font-weight: bold;">Until</span> i = 256<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
<br />
&nbsp; &nbsp;i = i + 1<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> i &gt; 256 <span style="color: #8D38C9; font-weight: bold;">Then</span> i = 1<br />
<br />
&nbsp; &nbsp;v = a * Q(i) + c<br />
&nbsp; &nbsp;t = CDec(v - Int(v / ULL) * ULL)<br />
&nbsp; &nbsp;c = CDec(Int(t / UL))<br />
&nbsp; &nbsp;Q(i) = v - Int(v / UL) * UL<br />
<br />
&nbsp; &nbsp;MWC256_UINT32 = Q(i)<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span><br />
<br />
<span style="color: #008000;">'Signed integer : (-2^31 to 2^31-1) ?<br />
</span><span style="color: #008000;">'author : philben<br />
</span><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> MWC256_INT32(<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> Start <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span> = <span style="color: #00C2FF; font-weight: bold;">False</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span><br />
&nbsp; &nbsp;MWC256_INT32 = CLng(MWC256_UINT32(Start) - &amp;H7FFFFFFF)<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span><br />
<br />
<span style="color: #008000;">'Double : (0.0, 1.0) ?<br />
</span><span style="color: #008000;">'author : philben - v1.01<br />
</span><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> MWC256_Dbl(<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> Start <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span> = <span style="color: #00C2FF; font-weight: bold;">False</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span><br />
&nbsp; &nbsp;MWC256_Dbl = MWC256_UINT32(Start) * 2.32830643653869E-10<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>et le résultat des tests :</p>
<blockquote><p>
Entropy = 7.999985 bits per byte.</p>
<p>Optimum compression would reduce the size<br />
of this 11469916 byte file by 0 percent.</p>
<p>Chi square distribution for 11469916 samples is 245.85, and randomly<br />
would exceed this value 64.83 percent of the times.</p>
<p>Arithmetic mean value of data bytes is 127.4586 (127.5 = random).<br />
Monte Carlo value for Pi is 3.144400759 (error 0.09 percent).<br />
Serial correlation coefficient is -0.000303 (totally uncorrelated = 0.0).
</p></blockquote>
<p>Il semble que cette adaptation fonctionne bien et à l&rsquo;avantage d&rsquo;être plus rapide que les deux précédentes mais beaucoup plus lente que son équivalent en C et que Rnd&#8230;<br />
Pour avoir un ordre d&rsquo;idée, compter moins de 2 secondes par million de nombres générés.</p>
<p>Un autre inconvénient de mon portage est qu&rsquo;il n&rsquo;est validé que par moi (!) et je ne suis pas particulièrement fier de l&rsquo;initialisation de l&rsquo;algorithme&#8230;</p>
<p>@+</p>
<p>Philippe</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Générer des nombres aléatoires gaussiens</title>
		<link>https://blog.developpez.com/philben/p11194/vba-access/generer_des_nombres_aleatoires_gaussiens</link>
		<comments>https://blog.developpez.com/philben/p11194/vba-access/generer_des_nombres_aleatoires_gaussiens#comments</comments>
		<pubDate>Mon, 30 Jul 2012 18:01:55 +0000</pubDate>
		<dc:creator><![CDATA[philben]]></dc:creator>
				<category><![CDATA[VBA - Ms Access]]></category>
		<category><![CDATA[Aléatoire]]></category>
		<category><![CDATA[Algorithme]]></category>
		<category><![CDATA[Code VBA]]></category>
		<category><![CDATA[Loi normale]]></category>
		<category><![CDATA[Numérique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Je vous présente ici deux petites fonctions écrites en VBA qui permettent de générer des nombres pseudo-aléatoires à distribution normale. Une fonction de visualisation accompagne le tout. La 1ère méthode implémentée est celle de Box-Muller Public Function NormalRandomBM(Optional ByVal Esperance &#8230; <a href="https://blog.developpez.com/philben/p11194/vba-access/generer_des_nombres_aleatoires_gaussiens">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Je vous présente ici deux petites fonctions écrites en VBA qui permettent de générer des nombres pseudo-aléatoires à distribution normale. Une fonction de visualisation accompagne le tout.<br />
<span id="more-12"></span><br />
<strong>La 1ère méthode implémentée est celle de Box-Muller</strong></p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> NormalRandomBM(<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> Esperance <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 0, _ <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> EcartType <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 1, _ <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> ForceRandomize <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span> = <span style="color: #00C2FF; font-weight: bold;">False</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> <br />
<span style="color: #008000;">'Générateur de nombres pseudo-aléatoires à distribution normale selon la méthode de Box-Muller - Forme polaire <br />
</span><span style="color: #008000;">'Référence : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform <br />
</span><span style="color: #008000;">'Implementation en VBA par Philben - v1.1 - Free to use <br />
</span> &nbsp; <span style="color: #151B8D; font-weight: bold;">Static</span> isRandomize <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span>, isNextRandom <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span>, nextRandom <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> <br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> u <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span>, v <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span>, s <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> isRandomize <span style="color: #8D38C9; font-weight: bold;">Or</span> ForceRandomize <span style="color: #8D38C9; font-weight: bold;">Then</span> <br />
&nbsp; &nbsp; &nbsp; Randomize <br />
&nbsp; &nbsp; &nbsp; isRandomize = <span style="color: #00C2FF; font-weight: bold;">True</span> <br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> isNextRandom <span style="color: #8D38C9; font-weight: bold;">Then</span> <br />
&nbsp; &nbsp; &nbsp; NormalRandomBM = Esperance + (nextRandom * EcartType) <br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Else</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Do</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;u = Rnd() * 2 - 1 &nbsp; <span style="color: #008000;">'nombres aléatoires entre -1 et 1 <br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; v = Rnd() * 2 - 1 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = u ^ 2 + v ^ 2 <br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Loop</span> <span style="color: #8D38C9; font-weight: bold;">Until</span> s &gt; 0 <span style="color: #8D38C9; font-weight: bold;">And</span> s &lt; 1 <br />
&nbsp; &nbsp; &nbsp; s = Sqr(-2 * Log(s) / s) <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; nextRandom = v * s <br />
&nbsp; &nbsp; &nbsp; NormalRandomBM = Esperance + (u * s * EcartType) <br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span> <br />
&nbsp; &nbsp;isNextRandom = <span style="color: #8D38C9; font-weight: bold;">Not</span> isNextRandom <br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>&nbsp;<br />
<strong>Particularité</strong><br />
Cet algorithme génère deux nombres pseudo-aléatoires gaussiens d&rsquo;où la possibilité d&rsquo;en conserver un pour l&rsquo;appel suivant de la fonction.<br />
On conserve un des deux nombres générés dans une variable <strong>Static</strong> qui sera utilisée au prochain appel pour réduire le temps de calcul de la fonction.</p>
<p><strong>Paramètres de la fonction de Box-Muller</strong><br />
Le premier paramètre est la moyenne mu ou l&rsquo;<strong>espérance</strong> de la distribution normale.<br />
Le deuxième est l&rsquo;écart-type de la distribution gaussienne (doit être supérieur à 0)<br />
Par défaut, l&rsquo;espérance est égale à 0 et l&rsquo;écart-type à 1 ce qui correspond aux paramètres de la loi normale centrée réduite N(0;1).<br />
Le troisième paramètre (par défaut à faux) permet de forcer la réinitialisation du générateur de nombre aléatoires de VBA (Randomize). Dans tous les cas, le premier appel de la fonction lance Randomize. Cette première initialisation est sauvegardée dans la variable Static <strong>isRandomize</strong> qui passe alors à l&rsquo;état Vrai.</p>
<p><strong>2ème méthode de Kinderman &#8211; Monahan</strong><br />
J&rsquo;ai ajouté cet algorithme car il est 30% plus rapide en VBA que le précédent et me permet de générer plus de 3 millions de nombres gaussiens par seconde.</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> NormalRandomKM(<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> Esperance <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 0, _ <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> EcartType <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 1, _ <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> ForceRandomize <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span> = <span style="color: #00C2FF; font-weight: bold;">False</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> <br />
<span style="color: #008000;">'Générateur de nombres pseudo-aléatoires à distribution normale &nbsp;: Ratio method (Kinderman - Monahan) <br />
</span><span style="color: #008000;">'Implementation en VBA par Philben - v1.0 - Free to use <br />
</span> &nbsp; Const c <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 1.71552776992141 + 3.59296E-15 &nbsp; <span style="color: #008000;">'sqrt(8/e) <br />
</span> &nbsp; <span style="color: #151B8D; font-weight: bold;">Static</span> isRandomize <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span> <br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> u <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span>, v <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span>, x <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> isRandomize <span style="color: #8D38C9; font-weight: bold;">Or</span> ForceRandomize <span style="color: #8D38C9; font-weight: bold;">Then</span> <br />
&nbsp; &nbsp; &nbsp; Randomize <br />
&nbsp; &nbsp; &nbsp; isRandomize = <span style="color: #00C2FF; font-weight: bold;">True</span> <br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Do</span> <br />
&nbsp; &nbsp; &nbsp; v = Rnd() <br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Do</span>: u = Rnd(): <span style="color: #8D38C9; font-weight: bold;">Loop</span> <span style="color: #8D38C9; font-weight: bold;">While</span> u = 0 <br />
&nbsp; &nbsp; &nbsp; x = (v - 0.5) * c / u <br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Loop</span> <span style="color: #8D38C9; font-weight: bold;">Until</span> (x * x &lt; -4 * Log(u)) <br />
&nbsp;<br />
&nbsp; &nbsp;NormalRandomKM = Esperance + (x * EcartType) <br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>Les paramètres de la fonction sont identiques à la précédente.</p>
<p><strong>Limite des générateurs</strong><br />
Notre couple Randomize/Rnd n&rsquo;est pas une source parfaitement aléatoire de nombres entre 0 et 1[, on ne peut donc espérer un miracle concernant les nombres gaussiens générés&#8230; Dans l&rsquo;état, ces fonctions ne peuvent pas être utilisées pour un usage &lsquo;scientifique&rsquo;.<br />
Dans ce cas, il faudrait utiliser un meilleur générateur de nombres aléatoires type <strong>Mersenne Twister</strong> ou autres (<a href="http://blog.developpez.com/philben/p10822/ms-access-vba/un_meilleur_rng" title="Un meilleur RNG…" target="_blank">voir billet précédent</a>) et vérifier que la distribution est qualitativement correcte.</p>
<p><strong>Visualiser la distribution normale</strong><br />
La fonction suivante génère un visuel de la distribution normale centrée réduite des nombres aléatoires dans la fenêtre &lsquo;Exécution&rsquo; de l&rsquo;éditeur Visual Basic :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> VisuelNormalRandom()<br />
<span style="color: #008000;">'Visuel de la distribution des nombres aléatoires gaussiens - v1.1<br />
</span> &nbsp; Const cNbClasse <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span> = 16, cNbEcartType <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = 4, cRangeClasse <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span> = cNbEcartType / cNbClasse<br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, aCompte(-cNbClasse <span style="color: #8D38C9; font-weight: bold;">To</span> cNbClasse) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, NumClasse <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, lMax <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> r <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Double</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">For</span> i = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> 50000<br />
&nbsp; &nbsp; &nbsp; r = NormalRandomKM() / cRangeClasse<br />
&nbsp; &nbsp; &nbsp; NumClasse = Int(Abs(r))<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> Abs(r) &gt; NumClasse + 0.5 <span style="color: #8D38C9; font-weight: bold;">Then</span> NumClasse = NumClasse + 1<br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> NumClasse &lt;= cNbClasse <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;NumClasse = NumClasse * Sgn(r)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;aCompte(NumClasse) = aCompte(NumClasse) + 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> aCompte(NumClasse) &gt; lMax <span style="color: #8D38C9; font-weight: bold;">Then</span> lMax = aCompte(NumClasse)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<br />
&nbsp; &nbsp;<span style="color: #008000;">'Affiche la distribution<br />
</span> &nbsp; Debug.<span style="color: #151B8D; font-weight: bold;">Print</span> <span style="color: #800000;">&quot;Distribution des nombres aléatoires&quot;</span> &amp; vbCrLf &amp; <span style="color: #800000;">&quot;-----------------------------------&quot;</span><br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">For</span> i = <span style="color: #151B8D; font-weight: bold;">LBound</span>(aCompte) <span style="color: #8D38C9; font-weight: bold;">To</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(aCompte)<br />
&nbsp; &nbsp; &nbsp; r = i * cRangeClasse<br />
&nbsp; &nbsp; &nbsp; Debug.<span style="color: #151B8D; font-weight: bold;">Print</span> IIf(Sgn(r) &gt;= 0, <span style="color: #800000;">&quot; &quot;</span>, <span style="color: #800000;">&quot;&quot;</span>) &amp; Format(r, <span style="color: #800000;">&quot;0.0#&quot;</span>), <span style="color: #F660AB; font-weight: bold;">String</span>(CDbl(aCompte(i)) / lMax * 50 + 1, <span style="color: #800000;">&quot;=&quot;</span>)<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>Coller l&rsquo;ensemble des fonctions dans un module standard. Si la fenêtre d&rsquo;exécution n&rsquo;est pas visible, appuyer sur Ctrl+G puis mettre le focus dans la fonction précédente et appuyer sur F5 pour l&rsquo;exécuter.</p>
<p>Vous devriez obtenir à peu près ceci :<br />
<img src="http://philben.developpez.com/DistributionGaussienne.png" alt="Distribution gaussienne des nombres aléatoires" /></p>
<p>Théoriquement, 68% des nombres générés sont dans l&rsquo;intervalle + ou &#8211; 1 écart-type autour de la moyenne, 95% entre 2 écarts-types et 99,7% entre 3 écarts-types.</p>
<p>Pour aller plus loin sur le sujet, <a href="http://www.doc.ic.ac.uk/~wl/papers/07/csur07dt.pdf">cette publication</a> récente passe en revue de nombreuses méthodes et algorithmes.</p>
<p>@+</p>
<p>Philippe</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TOP 3 aléatoire avec regroupement</title>
		<link>https://blog.developpez.com/philben/p11047/sql-access/top_3_aleatoire_avec_regroupement</link>
		<comments>https://blog.developpez.com/philben/p11047/sql-access/top_3_aleatoire_avec_regroupement#comments</comments>
		<pubDate>Sat, 26 May 2012 08:50:06 +0000</pubDate>
		<dc:creator><![CDATA[philben]]></dc:creator>
				<category><![CDATA[SQL - Ms Access]]></category>
		<category><![CDATA[Aléatoire]]></category>
		<category><![CDATA[Requête SQL]]></category>
		<category><![CDATA[Top]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Un internaute souhaitait extraire aléatoirement 3 Id d&#8217;une table pour chaque personne. C&#8217;est possible ! Création de la table et insertion des données La table tTop contient une colonne Id (clef primaire) et le nom de la personne Public Function &#8230; <a href="https://blog.developpez.com/philben/p11047/sql-access/top_3_aleatoire_avec_regroupement">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Un internaute souhaitait extraire aléatoirement 3 Id d&rsquo;une table pour chaque personne. C&rsquo;est possible !<br />
<span id="more-25"></span><br />
<strong>Création de la table et insertion des données</strong><br />
La table tTop contient une colonne Id (clef primaire) et le nom de la personne</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> CreationTableTop() <br />
&nbsp; &nbsp;Const cInsert <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span> = <span style="color: #800000;">&quot;INSERT INTO tTop (Nom) VALUES &quot;</span> <br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, Maxi <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span> <br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> aNoms <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Variant</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">With</span> DoCmd <br />
&nbsp; &nbsp; &nbsp; .SetWarnings <span style="color: #00C2FF; font-weight: bold;">False</span> <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; .RunSQL <span style="color: #800000;">&quot;CREATE TABLE tTop (Id AUTOINCREMENT CONSTRAINT PrimaryKey PRIMARY KEY, Nom CHAR);&quot;</span> <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">'VBA.Array impose que le tableau débute à l'indice 0 (Array de la librairie VBA) <br />
</span> &nbsp; &nbsp; &nbsp;<span style="color: #008000;">'Autre solution : OPTION BASE 0 en tête du module <br />
</span> &nbsp; &nbsp; &nbsp;aNoms = VBA.Array(<span style="color: #800000;">&quot;Albert&quot;</span>, <span style="color: #800000;">&quot;Marcel&quot;</span>, <span style="color: #800000;">&quot;Bernard&quot;</span>) <br />
&nbsp; &nbsp; &nbsp; Maxi = <span style="color: #151B8D; font-weight: bold;">UBound</span>(aNoms) + 1 <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; Randomize <br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> 50 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.RunSQL cInsert &amp; <span style="color: #800000;">&quot;('&quot;</span> &amp; aNoms(Int(Rnd() * Maxi)) &amp; <span style="color: #800000;">&quot;');&quot;</span> <br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> i <br />
&nbsp; &nbsp; &nbsp; .RunSQL cInsert &amp; <span style="color: #800000;">&quot;('Dominique');&quot;</span> <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; .SetWarnings <span style="color: #00C2FF; font-weight: bold;">True</span> <br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">With</span> <br />
&nbsp; &nbsp;MsgBox <span style="color: #800000;">&quot;Création terminée&quot;</span> <br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p><strong>Difficultés</strong><br />
La première difficulté est d&rsquo;obtenir un top 3 pour chaque Nom. Une solution consiste à filtrer les enregistrements en imposant les Id par Nom grâce à une sous-requête corrélée (WHERE T.Nom=T1.Nom) dans la clause IN :</p>
<div class="codecolorer-container sql blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SELECT</span> &nbsp;<span style="color: #66cc66;">*</span><br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; &nbsp;tTop <span style="color: #993333; font-weight: bold;">AS</span> T1<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp; T1<span style="color: #66cc66;">.</span>Id <span style="color: #993333; font-weight: bold;">IN</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> TOP <span style="color: #cc66cc;">3</span> Id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; tTop T<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;T<span style="color: #66cc66;">.</span>Nom <span style="color: #66cc66;">=</span> T1<span style="color: #66cc66;">.</span>Nom<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> T<span style="color: #66cc66;">.</span>Id<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> T1<span style="color: #66cc66;">.</span>Nom<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;T1<span style="color: #66cc66;">.</span>Id;</div></div>
<p>Le problème du Top 3 par Nom étant résolu, le plus compliqué reste à faire&#8230; Comment obtenir aléatoirement des Id pour chaque Nom ?<br />
En effet, on souhaite suffisamment d&rsquo;aléatoire pour que la liste des Id différe d&rsquo;un appel à l&rsquo;autre de la requête mais pas trop non plus pour que la sous-requête sorte la même liste des Id pour chaque T1.Id.<br />
L&rsquo;idée de base est d&rsquo;utiliser la fonction RND(T.Id) dans la clause ORDER BY pour trier aléatoirement les enregistrements en sachant que T.Id est unique :</p>
<div class="codecolorer-container sql blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SELECT</span> &nbsp;<span style="color: #66cc66;">*</span><br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; &nbsp;tTop <span style="color: #993333; font-weight: bold;">AS</span> T1<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp; T1<span style="color: #66cc66;">.</span>Id <span style="color: #993333; font-weight: bold;">IN</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> TOP <span style="color: #cc66cc;">3</span> Id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; tTop T<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;T<span style="color: #66cc66;">.</span>Nom <span style="color: #66cc66;">=</span> T1<span style="color: #66cc66;">.</span>Nom<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> Rnd<span style="color: #66cc66;">&#40;</span>T<span style="color: #66cc66;">.</span>Id<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;t<span style="color: #66cc66;">.</span>Id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> T1<span style="color: #66cc66;">.</span>Nom<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;T1<span style="color: #66cc66;">.</span>Id;</div></div>
<p>Comme vous pouvez le constater, on perd la notion de Top 3 par Nom car pour chaque T1.Id, la sous-requête recalcule une liste d&rsquo;Id différente&#8230;</p>
<p><strong>La requête SQL finale</strong></p>
<div class="codecolorer-container sql blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SELECT</span> &nbsp;<span style="color: #66cc66;">*</span><br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; &nbsp;tTop <span style="color: #993333; font-weight: bold;">AS</span> T1<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp; T1<span style="color: #66cc66;">.</span>Id <span style="color: #993333; font-weight: bold;">IN</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> TOP <span style="color: #cc66cc;">3</span> Id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; tTop T<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;T<span style="color: #66cc66;">.</span>Nom <span style="color: #66cc66;">=</span> T1<span style="color: #66cc66;">.</span>Nom<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> Rnd<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-</span><span style="color: #66cc66;">&#40;</span> T<span style="color: #66cc66;">.</span>Id <span style="color: #66cc66;">+</span> Timer<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;t<span style="color: #66cc66;">.</span>Id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> T1<span style="color: #66cc66;">.</span>Nom<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;T1<span style="color: #66cc66;">.</span>Id;</div></div>
<p><strong>Explications</strong><br />
On s&rsquo;appuie sur deux particularités d&rsquo;Access :</p>
<p>La <strong>première</strong> est que si l&rsquo;on passe un nombre négatif en argument à la fonction Rnd(), elle retourne toujours le même nombre aléatoire. Ceci permet d&rsquo;avoir une liste constante d&rsquo;Id pour chaque Nom.</p>
<p>La <strong>deuxième</strong> va nous permettre d&rsquo;obtenir une liste différente d&rsquo;Id entre chaque appel de la requête principale. Pour ajouter un zeste d&rsquo;aléatoire on utilise la fonction Timer() en argument de la fonction Rnd(). Heureusement, Access ne met pas à jour le timer() pendant tout le temps d&rsquo;exécution de la requête. La valeur du timer au démarrage de la requête est conservé jusqu&rsquo;à la fin de son exécution ou de sa prochaine actualisation (dans un formulaire prendre un recordset avec <strong>snapshot</strong> pour éviter une mise à jour via modification du jeu d&rsquo;enregistrements sous-jacent).</p>
<p><strong>Remarques</strong><br />
L&rsquo;ajout d&rsquo;une deuxième colonne de tri (T.Id) dans la sous-requête permet de s&rsquo;assurer que le top 3 retournera toujours que 3 lignes au maximum même si des ex-aequo subsistent après ORDER BY RND(-(T.Id+Timer())).</p>
<p>La présence de la sous-requête entraîne un temps d&rsquo;exécution long de la requête qui sera donc réservée pour des tables ayant peu de lignes (~1000).<br />
@+</p>
<p>Philippe</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
