Derniers messages sur Zeste de Savoirhttps://zestedesavoir.com/forums/2022-03-12T15:44:06+01:00Les derniers messages parus sur le forum de Zeste de Savoir.JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414812022-03-12T15:44:06+01:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241481<p>Remarques en vrac:</p>
<ol>
<li>
<p>C’est facile à dire après coup, mais je ne suis pas surpris par les résultats de tes tests. (Je n’ai pas compris ce que montre le troisième graphique et je n’arrive pas à le lire, donc je ne dis rien de celui-là.) Canoniser tout le temps coûte cher, c’est connu, et ta fonction de hash est (soyons francs) pourrie, on l’a déjà dit aussi.</p>
</li>
<li>
<p>Pour une approche où tu mets tout le temps en forme canoniques, il doit y avoir des optimisations que tu n’as pas essayé. Par exemple, stocker l’information de si un terme est canonique ou pas, et récrire les nombres en place quand on le met en forme canonique (au lieu de renvoyer un nouveau nombre). Il y a aussi peut-être des algorithmes malins pour accélérer le calcul du GCD de nombres obtenus par calculs fractionnaires sur des fractions déjà simplifiées/canoniques.</p>
</li>
<li>
<p>Ce que j’avais proposé plus haut, c’est de mettre en forme canonique au moment du hash, en modifiant le nombre en place (donc: hasher plusieurs fois ne refait pas de travail inutile). C’est sûrement moins coûteux que mettre tout le temps en forme canonique, mais évidemment ça dépend des cas d’usage de <code>hash</code> dans un vrai programme, et donc ça va être plus difficile à benchmarker de façon représentative. </p>
</li>
<li>
<p>Comme l’a dit Jacen, ne jamais mettre en forme canonique tue aussi les performances, puisque tu te retrouves vite avec des numérateurs et dénominateurs énormes. Aujourd’hui par exemple "sum" est un peu une blague, le coût est au minimum quadratique en la taille du tableau d’entrée. </p>
</li>
<li>
<p>Et donc avec l’approche actuelle de ta bibliothèque, où la bibliothèque elle-même ne canonise jamais, c’est l’utilisateur qui a la responsabilité de canoniser au bon moment pour avoir les meilleures performances. C’est un sacré problème d’utilisabilité — faites le bien et vous aurez de bonne perf, soyez naï-f-ve-s et votre code va exploser. Mais en même temps, les gens qui ont besoin de ce genre de libs sont souvent des expert-e-s d’un domaine pointu, donc une approche "full control" peut se justifier.</p>
</li>
<li>
<p>Ça donne envie d’expérimenter avec des modes de mise en forme canonique "de temps en temps", qui se font automatiquement dans la bibliothèque, moins bien que des utilisateurs. Par exemple, "canoniser toutes les N opérations", ou "canoniser quand le dénominateur dépasse une certaine borne" (avec la borne qui est doublée à chaque dépassement, comme les tableaux dynamiques qu’on augmente exponentiellement, etc.). Pas facile mais intéressant comme questions, et sans doute déjà traitées dans la littérature sur le sujet, tu as regardé ? Idéalement tu aurais un truc avec un surcoût modeste, paramétrable, qui fait moins bien par défaut que les canonisations à la main des expert-e-s mais qui évite les gros problèmes si l’utilisateur ne fait pas les choses correctement.</p>
</li>
</ol>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414742022-03-12T13:22:29+01:00Kaladin/@Kaladinhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241474<p>Je partirais sans aucun doute sur la solution 2. J’enlèverais complètement la fonction <code>canonicalForm</code>, et modifierais les opérations de base pour qu’une fraction soit toujours sous forme canonique. Mais je ne suis pas vraiment le public cible, je ne code pas en Java. Pour mieux répondre, il faudrait savoir à quels besoins tu essaies de répondre avec ta bibliothèque.</p>
<p>Je suis incapable d’imaginer un cas d’utilisation de rationnels à plusieurs milliers de chiffres, qui plus est avec un fort besoin de performances. Si on part du principe que les calculs commencent avec des petites fractions, il faut soit un très grand nombre d’opérations, soit des opérations très improbables (mise à la puissance 1000), pour en arriver là. Pour ma part, je n’ai jamais utilisé de rationnels de plus d’une douzaine de chiffres au dénominateur, et c’était déjà pour des calculs un peu fous, du type résoudre une EDO par perturbations jusqu’au dixième ordre…</p>
<p>Par contre, un cas d’utilisation que j’estime plus probable (peut-être à tort ?), c’est de faire la somme de beaucoup de petites fractions. Mettons que j’ai plusieurs milliers de fractions dont le dénominateur est inférieur à 10. Le dénominateur de la somme ne sera pas plus grand que 2520 sous forme canonique, et son numérateur aura autour d’une dizaine de chiffres au plus. Mais en l’état, ta fonction <code>sum</code> va manipuler des fractions à plusieurs milliers de chiffres, et aura probablement des performances exécrables (sans parler de la mise en forme canonique à la fin, si je veux afficher le résultat).</p>
<p>Après, rien n’empêche de garder le meilleur des deux mondes. Tu pourrais par exemple faire en sorte que par défaut les fractions sont sous forme canonique, mais avoir une option qui désactive ce comportement pour ceux pour qui ça pose un problème (ou inversement).</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414652022-03-12T10:20:00+01:00Jacen/@Jacenhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241465<p>Perso, avoir une fonction <code>equals</code> avec un comportement différent de <code>CompareTo</code>, c’est le genre de surprises auquel je m’attends en C, mais dans un autre langage, je m’attends à ce que la fonction fasse quelque chose de cohérent avec le type manipulé.</p>
<p>Après, en tant qu’utilisateur d’une lib de nombres, je m’attends à ce que les calculs soient rapides. Intuitivement, je privilégierais une solution où les nombres ne sont pas canoniques tant qu’on ne le demande pas. La comparaison de deux nombres est assez simple: <code>a/b = c/d <=> a*d = b*c</code>, en tous cas plus simple qu’une recherche de PGCD + division par celui ci, par contre, la table de hachage est un cas d’usage compliqué: je ne vois pas comment éviter de canoniser les nombres avant de les insérer ou chercher dans la table, et la structure est donc à réserver aux cas ou le coût de la canonisation est inférieur à celui de la comparaison avec chaque élément de la table. Cela dit, ça me choque pas, sur une lib de calculs, de regarder à combien de multiplications est équivalente une canonisation, et de recommander de ne pas utiliser les maps avec moins de valeurs que ce rapport. Ou sinon il faut faire une map qui ne repose pas sur un hash.</p>
<p>Cela dit, je me dis aussi qu’en ne canonisant jamais, les nominateurs et dénominateurs risquent de grandir à chaque opération mathématique, et, le temps de chaque opération dépendant de la taille du nombre, ça risque d’avoir un coût aussi à la fin. (cf point 2 de ton post initial)</p>
<p>Enfin bref, en tant qu’utilisateur, j’exclue les solutions 2 et 3. (Rien n’empêche d’avoir un nom autre que equals pour tester si deux nombres ont la même représentation, si c’est utile dans certains cas)</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414462022-03-11T22:07:22+01:00SpaceFox/@SpaceFoxhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241446<p>Alors : faites des tests. Les résultats pourraient vous surprendre.</p>
<div class="custom-block custom-block-question"><div class="custom-block-heading">J’aimerais votre avis !</div><div class="custom-block-body"><p>En tant qu’utilisateur d’une bibliothèque de calculs par les nombres rationnels, que préféreriez-vous entre les solutions suivantes ?</p><ol>
<li>Solution actuelle : les calculs sont rapides, <code>equals</code> a un comportement sans surprise (<code>3/6 == 4/8</code>), il faut demander explicitement la forme canonique. Les rationnels en tant que clés de <code>Map</code> ou dans un <code>Set</code> sont relativement lents, et surtout <strong>c’est relativement facile de forger une liste de nombre qui font effondrer les performances de ce qui utilise les hachages</strong>.</li>
<li>Les rationnels sont toujours sous forme canonique : <strong>toute création de rationnel est relativement lente, y compris les résultats des calculs</strong> (qui sont eux-mêmes rationnalisés, on parle d’un facteur 1 à 10 par rapport à une création sans canonisation selon la taille du nombre et la difficulté à trouver des facteurs communs). <code>equals</code> a un comportement sans surprise (<code>3/6 == 4/8</code>), les performances sont assez homogènes, les rationnels en tant que clés de <code>Map</code> ou dans un <code>Set</code> ne posent aucun problème particulier.</li>
<li>La solution de la vitesse (à la <code>BigDecimal</code>) : les calculs sont rapides, <strong><code>equals</code> a un comportement surprenant</strong> (<code>3/6</code> != <code>4/8</code>, il faut utiliser <code>compareTo</code> pour tester l’égalité de valeurs), il faut demander explicitement la forme canonique, les rationnels en tant que clés de <code>Map</code> ou dans un <code>Set</code> ne posent aucun problème particulier.</li>
<li><strong>Les rationnels sont passés sous forme canonique au besoin, et donc ne sont plus strictement immutables</strong>. On peut toujours demander cette forme canonique « à la main ». <code>equals</code> a un comportement sans surprise (<code>3/6 == 4/8</code>), <strong>le passage automatique sous forme canonique peut provoquer des baisses de performances imprévues</strong>, les rationnels en tant que clés de <code>Map</code> ou dans un <code>Set</code> ne posent aucun problème particulier mis à part le problème de performances susmentionné.</li>
<li>Autre, précisez.</li>
</ol><p>Évidemment j’ai mon idée, mais je serais curieux d’avoir des avis supplémentaires.</p></div></div>
<hr>
<p>Et donc, j’ai testé les formes 1, 2 et 3 du tableau ci-dessus.</p>
<figure><img src="/media/galleries/5662/cb71cfae-571d-43b4-bf75-88235eee61f7.png"><figcaption>Nombre de créations de <code>Rational</code> par seconde en fonction du nombre total de chiffres décimaux (numérateur + dénominateur). On voit qu’à partir de 16 chiffres (ce qui est vite atteint avec des chaines de calcul) l’utilisation de la forme canonique est sensiblement plus lente.</figcaption></figure>
<p>Ça c’est juste la création de nombres.</p>
<p>Les tests suivants fonctionnent de la façon suivante : on crée une liste de <code>n</code> nombres, avec, <code>i</code> de 0 à <code>n</code>, de la forme <code>(1 000 000 000 + i) / 1 000 000 000</code> (donc que des nombres très proches mais supérieurs à 1). Ces nombres ont la particularité, avec le code actuel, de tous donner un <code>hashCode</code> de 1, ce qui est donc le pire cas possible si on les mets dans une collection hachée (un seul hash pour toute la collection).</p>
<figure><img src="/media/galleries/5662/d7c8162b-df6b-4616-91cd-8eb5fb9b5d47.png"><figcaption>Nombre de créations d’un <code>Set</code> de ces nombres en fonction de la taille dudit <code>Set</code> (le <code>n</code> ci-dessus). <code>Rational</code> est l’implémentation actuelle, <code>Rational2</code> force les formes canoniques, <code>Rational3</code> a un <code>equals</code> surprenant.</figcaption></figure>
<p>Là les résultats m’ont étonné, au point que j’ai vérifié le code et relancé une suite de tests (d’où les deux séries de points). En fait l’implémentation actuelle <code>Rational</code> est systématiquement plus lente que tout le reste et ce même pour des petites tailles de collection, surtout parce que le calcul du <code>hashCode</code> est plus compliqué que dans les autres implémentations. Et ça, je ne m’y attendais pas, et surtout pas à ce point (combiné à la collision des hash, on atteint très vite un facteur 10 par rapport à une insertion d’un rationnel optimisé pour les performances !).</p>
<figure><img src="/media/galleries/5662/a92d0762-e669-4ba9-8e5b-8dad43ec19e9.png"><figcaption>Nombre de lectures dans une <code>Map<Rational, Object></code> par seconde, en fonction du nombre d’entrées dan ladite <code>Map</code> (le <code>n</code> ci-dessus). Les chiffres 1, 2 et 3 correspondent aux options de la question</figcaption></figure>
<p>On voit très bien que chercher une clé absente ou une clé dans une <code>Map</code> correctement indexée se fait très rapidement et en <code>O(1)</code> ; par contre le moindre défaut dans la répartition des hash a un impact catastrophique sur les performances, <em>et ce même sur les petites <code>Map</code>s</em> (un facteur 20 sur une <code>Map</code> de 10 clés). Par contre, la pénalité croit <em>relativement</em> peu vite avec la taille de la <code>Map</code>, en première approche je dirais que c’est du <code>O(log(n))</code>. Là aussi, je suis surpris : je ne m’attendais pas à un défaut aussi important aussi tôt, par contre je m’attendais à un perte plus importante sur les grandes <code>Map</code>.</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414412022-03-11T17:39:59+01:00SpaceFox/@SpaceFoxhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241441<p>Pour <code>sum</code>/<code>addAll</code>, après tests, je n’ai aucune différence d’efficacité effective (les différence sont toutes dans les erreurs de mesure). Et la différence de verbosité se joue à une poignée de caractères. Donc je garde l’implémentation que je trouve la plus logique et lisible.</p>
<div class="custom-block custom-block-spoiler"><div class="custom-block-body"><p><code>addAll</code> et <code>sum</code> sont les implémentations actuelles, <code>addAll2</code> et <code>sum2</code> sont les implémentations dans l’autre sens ; <code>addAll</code> et <code>addAll2</code> additionnent un nombre de <code>N</code> chiffres décimaux avec 100 nombres de même taille ; <code>sum</code> et <code>sum2</code> additionnent 100 nombres de <code>N</code> chiffres décimaux. Les séries de nombres utilisées sont identiques entre toutes les opérations et pour toutes les itérations (d’où les variations de mesures de l’ordre de 1%).</p><p>Cela dit, le système mériterait une étude approfondie des performances parce que je trouve ça lent, même si l’addition n’est pas l’opération la plus simple avec les rationnels (la multiplication est plus rapide par exemple).</p><div class="hljs-code-div hljs-code-text"><div class="hljs-line-numbers"><span data-count="1"></span><span data-count="2"></span><span data-count="3"></span><span data-count="4"></span><span data-count="5"></span><span data-count="6"></span><span data-count="7"></span><span data-count="8"></span><span data-count="9"></span><span data-count="10"></span><span data-count="11"></span><span data-count="12"></span><span data-count="13"></span><span data-count="14"></span><span data-count="15"></span><span data-count="16"></span><span data-count="17"></span></div><pre><code class="hljs language-text">Benchmark (size) Mode Cnt Score Error Units
SumVsSum2.addAll 10 thrpt 6 65320,976 ± 585,561 ops/s
SumVsSum2.addAll 100 thrpt 6 3085,038 ± 51,613 ops/s
SumVsSum2.addAll 1000 thrpt 6 93,395 ± 1,007 ops/s
SumVsSum2.addAll 10000 thrpt 6 0,365 ± 0,003 ops/s
SumVsSum2.addAll2 10 thrpt 6 66836,846 ± 878,029 ops/s
SumVsSum2.addAll2 100 thrpt 6 3076,949 ± 31,093 ops/s
SumVsSum2.addAll2 1000 thrpt 6 93,063 ± 0,664 ops/s
SumVsSum2.addAll2 10000 thrpt 6 0,366 ± 0,003 ops/s
SumVsSum2.sum 10 thrpt 6 68822,368 ± 723,198 ops/s
SumVsSum2.sum 100 thrpt 6 3121,855 ± 18,989 ops/s
SumVsSum2.sum 1000 thrpt 6 95,146 ± 1,182 ops/s
SumVsSum2.sum 10000 thrpt 6 0,374 ± 0,016 ops/s
SumVsSum2.sum2 10 thrpt 6 62064,412 ± 1857,949 ops/s
SumVsSum2.sum2 100 thrpt 6 3133,087 ± 27,517 ops/s
SumVsSum2.sum2 1000 thrpt 6 95,291 ± 0,579 ops/s
SumVsSum2.sum2 10000 thrpt 6 0,379 ± 0,005 ops/s
</code></pre></div></div></div>
<p>Pour <code>equals</code> et <code>hashCode</code>, quand je parle de tests, je parle bien de tester les cas pathologiques (par exemple avec plusieurs millions d’entrées qui ont le même <code>hashCode</code>) et de vérifier ce que ça donne. Une autre solution serait d’esquiver le problème et de faire comme <code>BigDecimal</code> et de considérer que deux <code>Rational</code> ne sont égaux que s’ils ont le même dénominateur et le même numérateur (aujourd’hui ils sont égaux si les valeurs sont égales) – et là on peut juste faire un <code>hashCode</code> à partir des valeurs des champs de la classe. Par exemple pour <code>BigDecimal</code>, <code>2.0</code> et <code>2.00</code> ne sont pas équivalents, et il faut faire <code>a.compareTo(b) == 0</code> pour tester l’égalité de valeur. Ce qui est pénible à l’utilisation et source de nombreuses erreurs. De plus dans le cas de <code>BigDecimal</code>, la notion d’« échelle » fait que la différence entre <code>equals</code> et <code>compareTo</code> me semble moins artificielle qu’avec la représentation des rationnels.</p>
<p>Bref, c’est pas un sujet trivial.</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414342022-03-11T16:07:15+01:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241434<p>Oui, <code>addAll</code> peut rester légèrement plus verbeux et moins efficace que nécessaire, ça n’a sans doute pas beaucoup d’importance en pratique.</p>
<p>Pour le hash, c’est une question plus compliquée. Une fonction de hash ayant un mauvais comportement peut nuire aux performances en régime "normal", mais c’est surtout un risque de faille de sécurité (denial of service) en pourrissant un programme avec des entrées bien choisies pour générer beaucoup de conflits. (Cela dépend de si la communauté utilise en général des tables de hashages où les "buckets" de valeurs ayant le même hash sont cherchées en O(n) ou en O(log n). En Java il me semble qu’on est dans le cas O(n) où ça se passe très mal très vite.) Une fonction de hash qui génère des conflits inutiles, c’est avant tout une mauvaise conception dont les coûts sont difficiles à évaluer, et donc à mon avis qu’il vaut mieux éviter par principe — même dans les cas où on n’imagine pas vraiment de cas d’usages problématiques.</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414202022-03-11T11:46:38+01:00SpaceFox/@SpaceFoxhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241420<p>Pour <code>addAll</code> et <code>sum</code>, je peux aussi laisser comme ça, ce qui fonctionne très bien et qui n’est qu’un détail d’implémentation. À moins qu’il y ait un intérêt à modifier la logique qui m’échappe complètement.</p>
<p>Pour <code>hashCode()</code>, ça va surtout demander des tests plus précis pour savoir à quel point la version actuelle pourrit les performances des classes qui l’utilisent. Parce que si j’explose les temps de toutes les utilisation pour en gagner un peu à la marge, ça n’est pas très intéressant <img src="/static/smileys/svg/hihi.svg" alt="^^" class="smiley"></p>
<p>Pour l’approximation, il semblerait qu’il y a quelque chose à faire avec les fractions continues.</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414172022-03-11T11:00:18+01:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241417<p>Sur <code>addAll</code>: tu peux définir <code>sum(xs)</code> comme <code>zero.addAll(xs)</code>.</p>
<p>Sur le hash: vu la spécification que tu te fixes, tu es obligé de canoniser la valeur avant de hasher.</p>
<p>Remarque: quand tu canonises une valeur, tu peux la récrire en place et donc gagner du temps sur les opérations suivantes sur la valeur. (En particulier hasher plein de fois un rationnel ne doit canoniser qu’une fois.) Peut-être que tu pourrais stocker un booléen "je suis déjà en forme canonique" pour éviter de canoniser plusieurs fois d’affilée la même valeur.</p>
<p>Sur l’approximation: je n’ai pas réfléchi non plus mais ça ressemble à un problème classique, avec en ligne une description de comment faire par une méthode assez simple (mais potentiellement coûteuse, si tu veux garantir l’optimalité de l’approximation). Je dirais de chercher sur internet "best rational approximation".</p>
<p>Mais même avec la spec actuelle "on utilise exactement le dénominateur fourni", je ne suis pas sûr que ton code actuel soit correct, les divisions d’entiers perdent beaucoup d’information. </p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414142022-03-11T10:45:41+01:00SpaceFox/@SpaceFoxhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241414<p>Merci pour ces remarques pertinentes !</p>
<figure><blockquote>
<ol>
<li>Je ne comprends pas bien l’intérêt d’implémenter des opérations réelles (racines, trigonométrie) sur des rationnels. Pourquoi ne pas faciliter l’interopérabilité avec une bibliothèque de calculs réels en précision infinie, et basculer vers des réels si on veut ces opérations ?</li>
</ol>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241412">gasche</a></figcaption></figure>
<p>Parce que ce qui m’intéresse le plus c’est précisément comment faire ces approximation. Ce projet, c’est principalement de la curiosité intellectuelle et méthodologique, qui me permet de répondre à des questions comme : comment on fait ce genre de calculs ? Qu’est-ce que ça implique en terme de performances ? Comment ça se comporte par rapport aux flottants standard ? Est-ce qu’écrire une bibliothèque pour quelque chose qui est souvent considéré comme plus ou moins <em>trivial</em> (la gestion basique des rationnels) est vraiment si <em>trivial</em> ? Etc. En fait je n’ai même pas de cas d’usage réel de cette bibliothèque <img src="/static/smileys/svg/hihi.svg" alt="^^" class="smiley"></p>
<p>Si je trouve une bibliothèque de calculs réels en précision infinie en pur Java, ajouter une passerelle serait un développement futur intéressant.</p>
<blockquote>
<ol start="2">
<li>Tu ne précises pas clairement la spécification de <code>approximate(denominatorMax)</code>. Intuitivement on s’attendrait à obtenir la meilleure approximation possible avec un dénominateur inférieur à <code>denominatorMax</code>. Ton code ne fait sans doute pas ça, et de loin (mais je n’ai pas réfléchi très fort) on dirait qu’il perd inutilement de la précision. En particulier, il faudrait sans doute commencer par normaliser avant d’approximer.
C’est une opération délicate, idéalement elle devrait (1) être spécifiée clairement et (2) avoir une implémentation bien expliquée qui justifie qu’elle respecte la spécification.</li>
</ol>
</blockquote>
<p>Sur ce point, c’est parce que je sais que ma méthode d’approximation actuelle est pourrie, en particulier parce qu’elle force le dénominateur fourni (s’il y a une approximation à faire) au lieu d’approximer au plus proche. Ça implique de trouver une méthode d’approximation qui fonctionne (en un temps raisonnable), chose à laquelle je n’ai pas assez réfléchi. Si quelqu’un a des pistes, je suis preneur.</p>
<figure><blockquote>
<ol start="3">
<li>Les constructeurs <code>of</code> ne mettent pas en forme canonique, mais ils normalisent le placement du signe sur le numérateur. Est-ce vraiment utile ? Ça fait un petit surcoût à chaque opération qui n’est sans doute pas nécessaire. (Ne pas normaliser le signe rend <code>abs</code> un poil plus coûteuse, mais c’est une opération rare.)</li>
</ol>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241412">gasche</a></figcaption></figure>
<p>En fait à l’origine tous les constructeurs mettaient sous forme canonique, mais c’est une catastrophe en terme de performances. Par contre normaliser le signe est pratiquement gratuit, et ne simplifie pas que <code>abs</code> mais aussi les égalités et les comparaisons.</p>
<figure><blockquote>
<ol start="4">
<li>Tu as fait le choix de dupliquer plein de méthodes (<code>of</code> en particulier, mais aussi <code>...Value</code> par exemple) sur plein de types d’entrée proches mais différents, pour ajouter du confort à l’utilisateur. Est-ce vraiment utile ? Tu pourrais aussi gérer seulement le cas "un BigInteger" et "deux BigInteger", et laisser les utilisateurs faire les conversions de leur côté.</li>
</ol>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241412">gasche</a></figcaption></figure>
<p>Oui. Le confort de l’utilisateur ne coute pas grand-chose pour la lib, et fait <em>beaucoup</em> dans sa facilité d’utilisation – surtout si je conserve seulement les <code>BigInteger</code> en entrée, parce que ça devient très vite très verbeux en Java.</p>
<p>Je développe ma bibliothèque telle que j’aimerais bien qu’elle soit si je devais l’utiliser. Et ça faisait aussi partie du test : à quel point c’est un surcout d’ajouter du confort d’utilisation ?</p>
<figure><blockquote>
<ol start="5">
<li>Pas convaincu par le wrapper <code>identityOperation</code>, ça fait beaucoup de tests pour des cas rares, et ça ne suffit pas pour exprimer toute la logique des "cas raccourcis" (<code>multiply</code> a toujours des tests à la main). Je pense qu’il serait aussi simple de calculer "normalement" les numérateurs et dénominateurs, et ensuite renvoyer <code>this</code> ou l’argument si on détecte qu’ils sont physiquement égaux au résultat. (<code>BigInteger</code> optimise déjà l’ajout de 0, et sans doute aussi (mais je n’ai pas vérifié) la multiplication par 1.)</li>
</ol>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241412">gasche</a></figcaption></figure>
<p>On est d’accord, ce wrapper va très certainement sauter.</p>
<figure><blockquote>
<ol start="6">
<li>La façon de calculer le hash est assez louche, tu vas hasher plein de nombres différents et proches sur la même valeur (par exemple : 3/4, 4/4, 5/4, 6/4, 7/4), ça sent les risques de comportements pathologiques sur les tables de hachage derrière.</li>
</ol>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241412">gasche</a></figcaption></figure>
<p>Là aussi je suis assez d’accord sur les risques, sauf que je suis un peu coincé par, d’une part le contrat de la paire <code>equals()</code>/<code>hashCode()</code>, et d’autre part le fait que je ne peux pas me permettre de normaliser les nombres à la création ou dans ces méthodes sous peine de faire exploser les performances en vol. En particulier, le problème vient de : <code>a.equals(b) == true</code> implique <code>a.hashCode() == b.hashCode()</code>, mais <code>a</code> et <code>b</code> peuvent être égaux et n’avoir aucun élément interne commun (par exemple : <code>2/4</code> et <code>3/6</code>).</p>
<p>Si quelqu’un a une meilleure idée, là aussi je prends.</p>
<figure><blockquote>
<ol start="7">
<li>Tu définis <code>addAll</code> en fonction de <code>sum</code>, j’aurais attendu l’inverse.</li>
</ol>
</blockquote><figcaption><a href="https://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241412">gasche</a></figcaption></figure>
<p>D’un point de vue logique pure, oui. D’un point de vue code, c’est plus logique dans ce sens, parce que <code>addAll</code> est une méthode d’objet mais <code>sum</code> est une méthode de classe, donc si je veux définir <code>sum</code> en fonction de <code>addAll</code>, il faut que je découpe ma collection, récupère le premier élément (ce qui n’est pas une opération triviale, vue que <code>Collection</code> n’est pas ordonnée, la notion de « premier élément » n’existe pas) et ajoute le reste de la collection.</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2414122022-03-11T10:13:55+01:00gasche/@gaschehttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241412<p>Quelques commentaires à chaud en regardant le code:</p>
<ol>
<li>
<p>Je ne comprends pas bien l’intérêt d’implémenter des opérations réelles (racines, trigonométrie) sur des rationnels. Pourquoi ne pas faciliter l’interopérabilité avec une bibliothèque de calculs réels en précision infinie, et basculer vers des réels si on veut ces opérations ?</p>
</li>
<li>
<p>Tu ne précises pas clairement la spécification de <code>approximate(denominatorMax)</code>. Intuitivement on s’attendrait à obtenir la meilleure approximation possible avec un dénominateur inférieur à <code>denominatorMax</code>. Ton code ne fait sans doute pas ça, et de loin (mais je n’ai pas réfléchi très fort) on dirait qu’il perd inutilement de la précision. En particulier, il faudrait sans doute commencer par normaliser avant d’approximer.
C’est une opération délicate, idéalement elle devrait (1) être spécifiée clairement et (2) avoir une implémentation bien expliquée qui justifie qu’elle respecte la spécification.</p>
</li>
<li>
<p>Les constructeurs <code>of</code> ne mettent pas en forme canonique, mais ils normalisent le placement du signe sur le numérateur. Est-ce vraiment utile ? Ça fait un petit surcoût à chaque opération qui n’est sans doute pas nécessaire. (Ne pas normaliser le signe rend <code>abs</code> un poil plus coûteuse, mais c’est une opération rare.)</p>
</li>
<li>
<p>Tu as fait le choix de dupliquer plein de méthodes (<code>of</code> en particulier, mais aussi <code>...Value</code> par exemple) sur plein de types d’entrée proches mais différents, pour ajouter du confort à l’utilisateur. Est-ce vraiment utile ? Tu pourrais aussi gérer seulement le cas "un BigInteger" et "deux BigInteger", et laisser les utilisateurs faire les conversions de leur côté.</p>
</li>
<li>
<p>Pas convaincu par le wrapper <code>identityOperation</code>, ça fait beaucoup de tests pour des cas rares, et ça ne suffit pas pour exprimer toute la logique des "cas raccourcis" (<code>multiply</code> a toujours des tests à la main). Je pense qu’il serait aussi simple de calculer "normalement" les numérateurs et dénominateurs, et ensuite renvoyer <code>this</code> ou l’argument si on détecte qu’ils sont physiquement égaux au résultat. (<code>BigInteger</code> optimise déjà l’ajout de 0, et sans doute aussi (mais je n’ai pas vérifié) la multiplication par 1.)</p>
</li>
<li>
<p>La façon de calculer le hash est assez louche, tu vas hasher plein de nombres différents et proches sur la même valeur (par exemple : 3/4, 4/4, 5/4, 6/4, 7/4), ça sent les risques de comportements pathologiques sur les tables de hachage derrière.</p>
</li>
<li>
<p>Tu définis <code>addAll</code> en fonction de <code>sum</code>, j’aurais attendu l’inverse.</p>
</li>
</ol>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2413702022-03-09T09:01:19+01:00SpaceFox/@SpaceFoxhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241370<p><del>Il faut que je vérifie, normalement le <code>.gitignore</code> utilisé gère ce cas et n’est censé partager que des fichiers utiles.</del></p>
<p>Vérifié, j’ai missclick à la génération du <code>.gitignore</code> et généré avec <code>intellij+iml</code> et pas <code>intellij+all</code>… faudra que je corrige ça.</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2413692022-03-09T07:45:49+01:00firm1/@firm1https://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241369<p>Chouette projet.</p>
<p>En lisant le code je m’aperçois que le dossier <code>.idea</code> a été publié sur github (avec des fichiers par forcément utile à partager). C’est un oubli ?</p>JVM-Rationals : Calculer dans ℚ avec la JVM, message #2413662022-03-08T22:01:00+01:00SpaceFox/@SpaceFoxhttps://zestedesavoir.com/forums/sujet/16104/jvm-rationals-calculer-dans-q-avec-la-jvm/?page=1#p241366<p>Salut les agrumes !</p>
<p>Le saviez-vous ? Il n’existe apparemment aucun moyen simple et standard de faire des calculs avec des nombres rationnes en Java. Il existe bien une classe <code>Fraction</code> chez Apache Commons qui est fonctionnelle mais très limitée, et une antique bibliothèque de sciences qui ne semble plus exister depuis des années… et <a href="https://github.com/thomasschuerger/rationalj">un projet récent et inconnu</a> dont je n’ai découvert l’existence qu’il y a quelques jours. Je passe sur les implémentations triviales donc très basiques qu’on trouve dans des coins du net.</p>
<p>C’est pourquoi je me suis mis en tête de faire ma propre bibliothèque pour ça. Plus parce que ça m’amuse et par intérêt technique (notamment ce que ça tire comme problèmes de performances) que pour vraiment l’utiliser, étant donné qu’en fait je n’en ai pas besoin.</p>
<p>Mon but était donc triple :</p>
<ol>
<li>Faire une bibliothèque qui fonctionne et utilisable par tout le monde (donc un minimum testée).</li>
<li>Faire des tests de performance dessus, par curiosité.</li>
<li>Implémenter des fonctions qu’on ne trouve pas sur les quelques implémentations trouvées, en particulier les puissances rationnelles et la trigonométrie. Ce qui implique de gérer des nombres approximatifs, puisque rien que <code>sqrt(2)</code> est un nombre irrationnel.</li>
</ol>
<p>L’avant-première version de tout ça est <strong>JRational</strong> (quelle originalité !) et <a href="https://github.com/JVM-Rationals/jrational">c’est disponible sous licence Apache 2.0 sur Github</a>.</p>
<p>C’est pas tout à fait une version 1.0.0 release (et donc ça n’est pas publié sur Maven Central / Sonatype), mais <a href="https://github.com/JVM-Rationals/jrational/releases">les <code>jar</code> et leurs signatures</a> sont disponibles, tout comme <a href="https://jvm-rationals.github.io/jrational/">la Javadoc</a>.</p>
<hr>
<p>Techniquement c’est du Java 11, même si rien ne s’oppose à ce que je puisse construire une version compatible Java 8 (il faut que je trouve comment faire avec ma version de Gradle qui tourne que sur Java 11+). Le code s’appuie massivement sur <code>BigDecimal</code> ce qui permet une précision arbitraire et virtuellement infinie (une paire d’entiers de deux milliards de nombres chacun…) mais du coup ne garantit absolument rien sur les performances.</p>
<p>J’ai fait des tests de performance (<a href="https://github.com/JVM-Rationals/jrational/tree/master/src/jmh/java/fr/spacefox/jrational">ils sont ici</a>, <code>./gradlew jmh</code> pour les lancer, comptez plus de 3 heures pour la suite complète…). Ils montrent que les performances sont tout à fait acceptables pour des nombres de taille raisonnable (grosso modo <code>O(1)</code> jusqu’à 32 chiffres décimaux au total dans le rationel (numérateur + dénominateur), après quoi on est grosso modo en <code>O(n)</code> avec <code>n</code> le nombre de chiffres, en occupation mémoire comme en temps de calcul sur les opérations de base. Il y a une cassure dans la pente des performances, qui doit correspondre à un effet de la taille du cache du processeur : avant, 2x plus de chiffres = 2x plus de temps de calcul ; après, 2x plus de chiffres = 3 à 4x plus de temps de calcul (à la louche hein).</p>
<p>Les deux enseignement que j’en ait tiré, c’est que :</p>
<ol>
<li>Forcer le stockage de la forme canonique n’est pas intéressant, parce que la pénalité de performances est trop importante (le passage sous forme canonique nécessitant de calculer un PGCD, ce qui est lent).</li>
<li>Par contre il faut une méthode pour calculer cette forme à la demande, parce que certains algorithmes produisent des nombres avec des très grands nombres de chiffres qui sont très facilement simplifiables. Par exemple <a href="https://github.com/JVM-Rationals/jrational/blob/master/src/test/java/fr/spacefox/jrational/RationalVsIee754Test.java#L183">celui-ci, sans la canonicalisation, ne finit pas pour cause de nombres de plusieurs millions de chiffres ; mais avec, le calcul se fait en quelques dizaines de ms</a>.</li>
<li>Il faut aussi une méthode pour arrondir les valeurs qui deviennent <em>trop</em> précises pour leur propre bien (une chaine de calculs peut donner un rationnel exact, mais exprimé sous la forme de deux entiers gigantesques, de plusieurs milliers de chiffres chacun).</li>
</ol>
<hr>
<p>Bref, voilà où j’en suis aujourd’hui, je vise une v1.0.0 le WE prochain.</p>
<p>Je suis preneur de tous vos retours et pourquoi pas vos merge request, sur tous les sujets, y compris la gueule de l’API, les performances et les corrections d’anglais <img src="/static/smileys/svg/heureux.svg" alt=":D" class="smiley"></p>
<p>Ah, et merci à <a href="/@Aabu" rel="nofollow" class="ping ping-link">@<span class="ping-username">Aabu</span></a>, <a href="/@Quentin" rel="nofollow" class="ping ping-link">@<span class="ping-username">Quentin</span></a> et <a href="/@KFC" rel="nofollow" class="ping ping-link">@<span class="ping-username">KFC</span></a> pour leurs articles sur les flottants sur ZdS (<a href="https://zestedesavoir.com/tutoriels/570/introduction-a-larithmetique-flottante/">ici</a>, <a href="https://zestedesavoir.com/billets/2149/comment-reordonner-une-somme-de-flottants-peut-changer-son-resultat/">ici</a> et <a href="https://zestedesavoir.com/articles/963/controler-la-propagation-des-erreurs-de-calculs-numeriques/">là</a>) qui m’ont donné des idées <a href="https://github.com/JVM-Rationals/jrational/blob/master/src/test/java/fr/spacefox/jrational/RationalVsIee754Test.java">de tests pour vérifier les intérêts et limites des calculs de rationnels par rapport aux flottants IEEE-754</a>.</p>
<hr>
<p>PS : dans ce qui est prévu aussi, c’est au moins une version Kotlin (et peut-être Groovy ?) qui permet d’utiliser la surcharge des opérateurs. Parce que sur des nombres, c’est quand même vachement pratique.</p>utiliser une bibliothèques, c++, message #2125012019-12-24T23:46:59+01:00cerveau/@cerveauhttps://zestedesavoir.com/forums/sujet/13368/utiliser-une-bibliotheques-c/?page=1#p212501<p>Merci de t’a réponse <a href="/membres/voir/sgble/" rel="nofollow" class="ping ping-link">@<span class="ping-username">sgble</span></a>,
je shouterais générer des paires de clé public et privée et je pense que la fonctions adapter est <code>int EC_KEY_generate_key(EC_KEY *key);</code> mais je ne sais pas comment l’utliser et j’ai du mal a comprendre la doc openssl, voici ce qui est dit dans la doc :</p>
<p>EC_KEY_generate_key génère une nouvelle clé publique et privée pour l' objet eckey fourni . eckey doit avoir un objet EC_GROUP associé avant d’appeler cette fonction. La clé privée est un entier aléatoire (0 <clé_privée <ordre, où ordre est l’ordre de l’objet EC_GROUP). La clé publique est un EC_POINT sur la courbe calculé en multipliant le générateur de la courbe par la clé privée.</p>
<p>Pouvez vous m’aidez svp ? Il n’ya aucun tuto sur l’utlisation d’openssl <img src="/static/smileys/pleure.png" alt=":'(" class="smiley"> </p>utiliser une bibliothèques, c++, message #2124862019-12-24T14:23:06+01:00sgble/@sgblehttps://zestedesavoir.com/forums/sujet/13368/utiliser-une-bibliotheques-c/?page=1#p212486<p>Si tu es sous un Unix, la doc est accessible dans les pages <code>man</code>.</p>
<p>Par exemple, <code>man crypto</code> donne :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-shell">CRYPTO(7SSL) OpenSSL CRYPTO(7SSL)
NAME
crypto - OpenSSL cryptographic library
SYNOPSIS
See the individual manual pages for details.
DESCRIPTION
The OpenSSL crypto library implements a wide range of cryptographic algorithms used in various Internet standards. The services
provided by this library are used by the OpenSSL implementations of SSL, TLS and S/MIME, and they have also been used to implement SSH,
OpenPGP, and other cryptographic standards.
</code></pre></div>
<p>En principe tu as la même chose en version Web ici : <a href="https://www.openssl.org/docs/man1.0.2/man3/">https://www.openssl.org/docs/man1.0.2/man3/</a>
(mais c’est assez indigeste, j’en conviens <img src="/static/smileys/triste.png" alt=":(" class="smiley"> Le mieux serait de trouver un bon livre ou un bon tutoriel qui expose OpenSSL je pense)</p>utiliser une bibliothèques, c++, message #2124712019-12-23T22:48:23+01:00cerveau/@cerveauhttps://zestedesavoir.com/forums/sujet/13368/utiliser-une-bibliotheques-c/?page=1#p212471<p>Ton article est très intéressant surtout que je cherche a comprendre la sécurité informatique,<br>
ton article parle du langage C , il y’a eu le même problème avec C++ ou pas ? </p>
<p>Pertinent mais Cela ne répond pas à ma question : </p>
<p>Comment utilise t-on une bibliothèque comme OpenSSL ? Exemple toi comment tu sais qu’il faut utiliser se code ? N’y a t-il pas une documentation OpenSSL ?</p>
<p>Car je cherche a générer une paire de clé public et privée à partir de l’algorithme EC(courbe elliptique), mais je ne sais pas comment utiliser l’algorithme.</p>utiliser une bibliothèques, c++, message #2124152019-12-23T08:37:34+01:00Ge0/@Ge0https://zestedesavoir.com/forums/sujet/13368/utiliser-une-bibliotheques-c/?page=1#p212415<p>Salut,</p>
<p>J’avais succinctement utilisé cette bibliothèque pour un programme d’exemple de <a href="https://zestedesavoir.com/articles/100/introduction-aux-buffer-overflows/">mon article sur les buffer overflows</a> :</p>
<div class="hljs-code-div"><div class="hljs-line-numbers"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div><pre><code class="hljs language-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><stdio.h></span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><stdlib.h></span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><string.h></span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><openssl/crypto.h></span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><openssl/md5.h></span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> BUFSIZE 40 <span class="hljs-comment">/* Should be enough */</span></span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
<span class="hljs-keyword">int</span> access_granted = <span class="hljs-number">0</span>;
<span class="hljs-keyword">char</span> password[BUFSIZE] = {<span class="hljs-string">'\0'</span>};
<span class="hljs-keyword">char</span> hash[<span class="hljs-number">16</span>] = {<span class="hljs-string">'\0'</span>};
<span class="hljs-built_in">printf</span>(<span class="hljs-string">"Enter the password to get the access granted! "</span>);
<span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%s"</span>, password);
MD5_CTX c;
MD5_Init(&c);
MD5_Update(&c, password, <span class="hljs-built_in">strlen</span>(password));
MD5_Final(hash, &c);
<span class="hljs-keyword">if</span>(<span class="hljs-built_in">memcmp</span>(<span class="hljs-string">"\x90\x6d\x6f\x6a\x61\x58\xd6\x9d\x18\x59\x85\x26\x70\xbe\xfb\x08"</span>, hash, <span class="hljs-number">16</span>) == <span class="hljs-number">0</span>) {
access_granted = <span class="hljs-number">1</span>;
}
<span class="hljs-keyword">if</span>(access_granted) {
<span class="hljs-built_in">printf</span>(<span class="hljs-string">"Access granted!\n"</span>);
execve(<span class="hljs-string">"/bin/sh"</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>);
} <span class="hljs-keyword">else</span> {
<span class="hljs-built_in">printf</span>(<span class="hljs-string">"!!! ACCESS DENIED !!!\n"</span>);
}
<span class="hljs-built_in">exit</span>(EXIT_SUCCESS);
}
</code></pre></div>
<p>N’oublie pas d’utiliser la directive <code>-lcrypto</code> lors de l’édition de liens.</p>
<p>Ce programme met en évidence l’exploitation d’une vulnérabilité, n’hésite pas à lire l’article pour la comprendre, c’est assez formateur ! Sans prétention aucune bien sûr…</p>
<p>À+.</p>utiliser une bibliothèques, c++, message #2124002019-12-22T16:05:15+01:00cerveau/@cerveauhttps://zestedesavoir.com/forums/sujet/13368/utiliser-une-bibliotheques-c/?page=1#p212400<p>Des bibliothèques en général car je pense avoir bien configurer openssl dans mon projet code::blocks, je voudrais donc tester pour savoir si c’est bien le cas.
Un genre de code test comme quand en créer un nouveau projet sur code::blocks il y’a un petit code a compiler.</p>utiliser une bibliothèques, c++, message #2123972019-12-22T14:50:58+01:00sgble/@sgblehttps://zestedesavoir.com/forums/sujet/13368/utiliser-une-bibliotheques-c/?page=1#p212397<blockquote>
<p>Comment coder en utilisant la bibliothèques, les fonctionnalités de celles-ci ? Comment utiliser une bibliothèque ?</p>
</blockquote>
<p>Ton problème est-il relatif à la bibliothèque OpenSSL, ou bien s’agit-il d’un problème plus général de compréhension du fonctionnement des bibliothèques en C++ ?</p>utiliser une bibliothèques, c++, message #2123802019-12-21T19:56:34+01:00cerveau/@cerveauhttps://zestedesavoir.com/forums/sujet/13368/utiliser-une-bibliotheques-c/?page=1#p212380<p>Bonjour, </p>
<p>Je viens d’installer OpenSSL mais je ne sais pas comment l’utiliser dans mon code pour chiffrer des données, Alors ma question est : Comment coder en utilisant la bibliothèques, les fonctionnalités de celles-ci ? Comment utiliser une bibliothèque ?</p>
<p>Par exemple moi je veux utiliser l’algorithme de la courbe elliptiques comment faire ? </p>Les descriptions vides sont affichées pour les contenus, message #2088102019-09-19T07:39:24+02:00anonyme/@anonymehttps://zestedesavoir.com/forums/sujet/13013/les-descriptions-vides-sont-affichees-pour-les-contenus/?page=1#p208810<p><del>J’ai tweetté <a href="https://zestedesavoir.com/tutoriels/2789/les-reseaux-de-zero/">https://zestedesavoir.com/tutoriels/2789/les-reseaux-de-zero/</a> il n’a pas de logo <img src="/static/smileys/triste.png" alt=":(" class="smiley"></del> <— Twitter a pris du temps pour les charger</p>