Derniers messages sur Zeste de Savoirhttps://zestedesavoir.com/forums/2015-04-10T19:56:35+02:00Les derniers messages parus sur le forum de Zeste de Savoir.La fonction factorielle, message #511852015-04-10T19:56:35+02:00Kje/@Kjehttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51185<p>Ça risque de pas le faire si ça doit etre multi threadé</p>La fonction factorielle, message #511822015-04-10T19:26:06+02:00Algue-Rythme/@Algue-Rythmehttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51182<p>Oui, mais… c'est cheaté, y a moins de prestige <img alt=":p" src="/static/smileys/langue.png"><br>
Ce serait totalement injuste de gagner avec ça, faut un minimum de challenge </p>
<p>Et j'ai bien envie de voir ce que donnerait ma méthode… </p>La fonction factorielle, message #511302015-04-10T14:48:05+02:00pierre_24/@pierre_24https://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51130<p>Probablement effectivement le plus opti qu'on puisse faire (à part peut-être appeler BLAS/Lapack au secours, qui doit être à mon avis très opti), mais effectivement moins drôle <img alt=";)" src="/static/smileys/clin.png"></p>La fonction factorielle, message #511232015-04-10T13:42:38+02:00fromvega/@fromvegahttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51123<p>La solution de facilité: appeler directement la fonction de la lib GMP calculant la factorielle, extrêmement optimisée, 10 lignes de code en C tout au plus.
Mais beaucoup moins passionnant que d'implémenter un algo soit même <img alt=":-)" src="/static/smileys/smile.png"></p>La fonction factorielle, message #510912015-04-10T08:07:26+02:00Kje/@Kjehttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51091<p>La lookup table est alors forcément le plus rapide mais ça risque d'être dur de le rendre parallèle</p>La fonction factorielle, message #510882015-04-10T02:06:06+02:00Tsu/@Tsuhttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51088<p>Woah merci beaucoup <img alt=":D" src="/static/smileys/heureux.png">
Pour la petite histoire, les solutions malhonnêtes sont autorisées.
J'ai reçu cette réponse d'un de mes profs :</p>
<table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="codehilite"><pre>Dans l'ordre :
Vous n'avez pas le droit d'avoir autre chose que du code C
Vous n'avez pas le droit d'écrire sur le disque
</pre></div>
</td></tr></table>
<p>Et la règle est que tout ce qui n'est pas interdit est autorisé.</p>
<p>J'avais pensé à cette décomposition en facteurs premiers. Je ne savais juste pas comment faire la décomposition rapidement <img alt=":)" src="/static/smileys/smile.png"></p>
<p>Je vais maintenant me remettre à mon code et faire plein de tests chronométrés. Je dois tester le temps que met une multiplication en fonction de sa base, de la technique utilisée, enfin un peu tout quoi. Je vous tiens au courant ! N'hésitez pas à continuer à proposer des choses en attendant si vous avez des idées !</p>La fonction factorielle, message #510782015-04-09T22:13:24+02:00Algue-Rythme/@Algue-Rythmehttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51078<p>Une idée comme ça en passant. </p>
<p>Pour calculer <mathjax>$n!$</mathjax> tu fais la décomposition en facteurs premiers des nombres de 1 à n.<br>
Ainsi plutôt de calculer le produit de 500 nombres, tu calcules le produits de ces nombres premiers, chacun avec leur multiplicité respective.<br>
Tu utilises karatsuba pour le produit de grands nombres, et l'exponentiation rapide pour les puissances de chaque nombre premier.<br>
Exemple avec 15! : </p>
<p><mathjax>$15! = 2\times 3\times 4\times 5\times 6\times 7\times 8\times 9\times 10\times 11\times 12\times 13\times 14\times 15$</mathjax></p>
<p><mathjax>$2 = 2$</mathjax><br>
<mathjax>$3 = 3$</mathjax><br>
<mathjax>$4 = 2\times 2$</mathjax><br>
<mathjax>$5 = 5$</mathjax><br>
<mathjax>$6 = 2\times 3$</mathjax><br>
<mathjax>$7 = 7$</mathjax><br>
<mathjax>$8 = 2\times 2\times 2$</mathjax><br>
<mathjax>$9 = 3\times 3$</mathjax><br>
<mathjax>$10 = 2\times5$</mathjax><br>
<mathjax>$11 = 11$</mathjax><br>
<mathjax>$12 = 2\times 2\times 3$</mathjax><br>
<mathjax>$13 = 13$</mathjax><br>
<mathjax>$14 = 2\times7$</mathjax><br>
<mathjax>$15 = 3\times 5$</mathjax> </p>
<p><mathjax>$15! = 2^{11}\times 3^6\times 5^3\times 7^2\times 11\times 13$</mathjax> </p>
<p>Pour des nombres de petites taille comme celui-là c'est assez peu criant. Mais quand les nombres deviennent grands je pense que ça devient intéressant.<br>
En effet le nombre de nombres premiers inférieurs à <mathjax>$n$</mathjax> tend vers <mathjax>$\frac{n}{\ln{n}}$</mathjax><br>
Tu peux les pré-calculer, <a href="http://noe-education.org/D11102.php">il y en a tout juste une centaine</a> inférieurs à 500.<br>
Dans ta factorielle, la puissance à laquelle il faudra porter chacun d'eux est donné par la formule de Legendre : </p>
<p><mathjax>$v_p(n!) = \sum_{k=1}^\infty \lfloor \frac{n}{p^k}\rfloor$</mathjax> </p>
<p>Cette somme est rapide à calculer, dans la pratique, puisque très vite, pour k = 3 ou k = 4, tu vas dépasser n. Mis à part pour 2, où k devra monter jusque 9, et 3, où k devra monter jusque 6.<br>
La puissance de chaque nombre premier, tu la calcules grâce à l'<a href="http://fr.wikipedia.org/wiki/Exponentiation_rapide">exponentiation rapide</a> (qui a une complexité en temps logarithmique). Sauf pour 2 (qui aura la puissance la plus élevée) : là tu triches et tu utilises un décalage bit à bit. Si la puissance de 2 vaut 200, bah tu décales simplement le 1 de 200 bits, ça va être très rapide.<br>
Et c'est là que le parallélisme interviens ! Tu lances un thread pour calculer les puissances de chaque nombre premier. En réalité, ce n'est rentable que pour les premiers nombres premiers, de 2 à 29 maxi, et encore ! En effet, les puissances de chaque nombres premiers vont devenir très vite très petites. Le temps que les premiers threads calculent des puissances élevée, le dernier aura eu le temps de calculer les produits de tout les autres nombres premiers de grande valeur et de puissances peu élevée. </p>
<p>Pour les produits de grands nombres tu utilises <a href="http://fr.wikipedia.org/wiki/Algorithme_de_Karatsuba">karatsuba</a> qui a une bonne complexité, surtout pour des nombres comme <mathjax>$500!$</mathjax>. Karatsuba n'est rentable que pour des nombres de plusieurs centaines de chiffres, mais là, on peut déjà minorer <mathjax>$500!$</mathjax> par <mathjax>$100^{400} = 10^{800} \simeq 2^{2660}$</mathjax> qui possède déjà pas mal de chiffres en base 10 comme en base 2.<br>
Tu peux éventuellement paralléliser le produit des différentes puissances de nombres premiers, en mettant chaque terme dans un tableau, et en faisant un diviser pour régner. </p>
<p>J'aurais bien du mal à évaluer la complexité de l'algo, et n'ayant jamais testé, je ne saurais pas dire si c'est efficace en pratique, ou juste séduisant. </p>
<p>PS :<br>
J'ai fait quelques calculs et il se trouve que le nombre de multiplications à réaliser sera très inférieur à 500 même pour calculer <mathjax>$700!$</mathjax> (c'est une majoration très haute). Dans la pratique je pense que ce sera entre 200 et 300, pour <mathjax>$700!$</mathjax>. </p>La fonction factorielle, message #510022015-04-09T11:28:36+02:00Fraggy/@Fraggyhttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p51002<p>+1 pour la lookup table, c'est de loin le plus efficace que tu puisse faire pour accélérer le calcul <img alt=":)" src="/static/smileys/smile.png"></p>La fonction factorielle, message #509872015-04-09T08:15:08+02:00Kje/@Kjehttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p50987<p>Oui gmp est pas mal et toujours plus efficace que du code a la main.</p>
<p>Au lieu de toutes les valeurs en dur tu peux toujours mettre un database. Pour gagner du temps, vu ton énoncé, tu peux dans tous les cas fixer en dur <mathjax>$500!$</mathjax> : ca t'economisera 498 multiplications pour chaque valeur testée</p>La fonction factorielle, message #509842015-04-09T03:56:32+02:00Tsu/@Tsuhttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p50984<p>C'est sans doute une bonne idée <img alt=":)" src="/static/smileys/smile.png"> Je vais faire des tests de perf avec et sans cette lib. Merci pour le lien. J'avoue que c'est la première fois que je me retrouve confronté à des grands nombres en C.</p>La fonction factorielle, message #509832015-04-09T03:37:42+02:00pierre_24/@pierre_24https://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p50983<p>La <a href="https://gmplib.org/">GMP</a> est relativement utilisé dans mon domaine (le calcul scientifique), je ne sais pas si ça peut aider ton problème de grand nombre. Après, peut-être que tu veux faire ça "toi même" <img alt="^^" src="/static/smileys/hihi.png"></p>La fonction factorielle, message #509802015-04-09T03:22:22+02:00Tsu/@Tsuhttps://zestedesavoir.com/forums/sujet/2822/la-fonction-factorielle/?page=1#p50980<p>Dans le cadre de mes études, j'ai un TP d'info toutes les semaines.
Ce coup ci, le TP est sur le multithreading. Je pense avoir assez bien compris le concept et comment m'en servir. Ici je viens vous demander un coup de main sur un exo en particulier.</p>
<p>On doit simplement écrire la fonction factorielle, mais voilà, il y a un scoreboard pour montrer qui a les meilleurs perfs dans la promo. Ayant une réputation de hardcore teckie à tenir dans cette école, je prends ce genre de défis à la con très au sérieux.
Le calcul doit obligatoirement être multithreadé. J'ai pensé à écrire une fonction qui multiplie les nombres de n à m. Ça permet de découper le calcul en petits fragments parallélisables. J'aurais donc pour factorielle 100 ce calcul :</p>
<table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="codehilite"><pre>thread <span class="m">1</span> : fact<span class="o">(</span>2, 10<span class="o">)</span> <span class="o">=</span> 3628800
thread <span class="m">2</span> : fact<span class="o">(</span>11, 20<span class="o">)</span> <span class="o">=</span> 670442572800
thread <span class="m">1</span> : fact<span class="o">(</span>21, 30<span class="o">)</span> <span class="o">=</span> 109027350432000
thread <span class="m">2</span> : fact<span class="o">(</span>31, 40<span class="o">)</span> <span class="o">=</span> 3075990524006400
thread <span class="m">1</span> : fact<span class="o">(</span>41, 50<span class="o">)</span> <span class="o">=</span> 37276043023296000
thread <span class="m">2</span> : fact<span class="o">(</span>51, 60<span class="o">)</span> <span class="o">=</span> 273589847231500800
thread <span class="m">1</span> : fact<span class="o">(</span>61, 70<span class="o">)</span> <span class="o">=</span> 1439561377475020800
thread <span class="m">2</span> : fact<span class="o">(</span>71, 80<span class="o">)</span> <span class="o">=</span> 5974790569203456000
thread <span class="m">1</span> : fact<span class="o">(</span>81, 90<span class="o">)</span> <span class="o">=</span> 20759078324729606400
thread <span class="m">2</span> : fact<span class="o">(</span>91, 100<span class="o">)</span> <span class="o">=</span> 62815650955529472000
</pre></div>
</td></tr></table>
<p>pendant ce temps là le thread 0 fait un join sur les deux autres (il les attend) puis il multiplie les dix résultats entre eux.</p>
<p>Là j'ai déjà deux problèmes. Premièrement, cette solution est sûrement très naïve, je suis sûr qu'il y a de bien meilleurs manières de faire. Je suis tombé là dessus : <a href="http://www.luschny.de/math/factorial/conclusions.html">http://www.luschny.de/math/factorial/conclusions.html</a> Je planche encore dessus.
Deuxièmement, ce TP est à faire en C. Les tests effectués par nos profs seront faits avec n compris entre 500 et 700. Evidemment, 500! dépasse déjà de loin la taille de tous les types d'entiers standard que je connais. Du coup je vais devoir bidouiller.</p>
<p>Ceci m'amène à mes questions :</p>
<ul>
<li>
<p>Est-ce que vous auriez des idées d'optimisations de la fonction factorielle ?</p>
</li>
<li>
<p>Qu'est-ce que vous suggérez comme manière de faire pour gérer des grands nombres en C sans perte de perfs.</p>
</li>
</ul>
<p>Toutes les idées sont les bienvenues. Je suis ouvert aux solutions les plus originales. Le seul objectif est la vitesse d'exécution. Je suis en train de vérifier si j'ai le droit de charger un tableau de 200 chaînes de caractères écrites à la main (résultats précalculés et mis en dur dans le code source héhé) et surtout si ça vaut le coup d'un point de vue perfs.
Je préfère éviter les instructions directement en assembleur tant que je ne connais pas la machine de tests.</p>
<p>Au fur et à mesure des idées proposées, je vais essayer de les implémenter, et je vous dirais quel est le temps pris par telle ou telle solution histoire qu'on parle pas juste dans le vide.</p>
<p>Merci pour votre lecture les agrumes !</p>