kantien a écrit 1131 commentaires

  • [^] # Re: un des

    Posté par  . En réponse à la dépêche Grammalecte, correcteur grammatical [2]. Évalué à 3. Dernière modification le 12 juin 2017 à 09:59.

    Liens intéressants mais aucun ne fournit, ou plutôt n'explique, le principe qui va régir la bonne formation grammaticale des phrases avec ce type de construction.

    Tentons la chose ! L'article « de » prend deux groupes (ou syntagmes) nominaux et forme un groupe nominal; exemples : la sœur de ma mère, un de ceux j'ai vu, le premier de la liste… On peut le voir comme un opérateur binaire infixe, et le groupe nominal produit hérite du genre et du nombre du paramètre de gauche; féminin singulier, masculin singulier et masculin singulier pour les exemples précédents.

    Viens maintenant la question de l'analyse d'une telle construction lorsqu'apparaît une subordonnée relative : à qui se réfère le pronom relatif « qui » ou « que » ? Il peut aussi bien se référer au groupe complet « x de y » que faire partie de la construction du groupe nominal qui constitue l'argument de droite de l'article « de ».

    Prenons, en exemple, la phrase du journal qui à soulever la question : « un des points auxquels je n’avais pas beaucoup réfléchi et qui m’a le plus surpris »; elle est grammaticalement erronée, mais peut donner naissance à celle-ci en supprimant le « et » :

    • un des (points auxquels je n’avais pas beaucoup réfléchi) qui m’a le plus surpris

    Ici, le groupe « points auxquels je n'avais pas beaucoup réfléchi » est bien formé (le verbe ne s'accorde pas, le syntagme « points » étant un COI). Ce groupe étant au pluriel l'article est mis à sa forme plurielle ( « de » devient « des »). Ensuite le sujet de l'auxiliaire avoir est le pronom relatif « qui » qui se réfère au syntagme nominal complet formé par la construction « un des … » : il est donc masculin singulier, et l'auxiliaire est bien conjugué.

    En revanche, la proposition de lecteur devrait se décomposer ainsi :

    • un des (points auxquels je n’avais pas beaucoup réfléchis et qui m’ont le plus surpris)

    ici, la subordonnée relative fait partie de la construction du syntagme nominal qui joue le rôle du second argument de l'article « de ». Le pronom relatif « qui » se réfère aux « points », le sujet est donc pluriel et l'auxiliaire est bien conjugué.

    Voilà les raisons pour lesquelles l'accord dépendra de ce que veut exprimer l'auteur. Selon le contexte dans lequel est employé la construction, il y a deux sujets possibles dont le choix dépend de la pensée à exprimer. D'où les trois constructions possibles suivantes :

    • un des (points auxquels je n’avais pas beaucoup réfléchis et qui m’ont le plus surpris)
    • un des (points auxquels je n’avais pas beaucoup réfléchi) qui m’a le plus surpris
    • (un des points) auquel je n’avais pas beaucoup réfléchi et qui m’a le plus surpris

    il semblerait que ce soit la dernière que voulait exprimer Olivier.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Il y a un mais !

    Posté par  . En réponse à la dépêche Grammalecte, correcteur grammatical [2]. Évalué à 6.

    On n’est déjà pas d’accord ça. Les radicaux du 1ᵉʳ sont souvent modifiés. Sinon je n’aurais pas eu besoin d’autant de règles pour gérer ça.

    C'est effectivement là que nous ne sommes pas d'accord : il ne s'agit pas là pour moi de ce que j'entendais par altération du radical.

    Dans tes exemples, on trouve d'abord les verbes en « -ger » et « -cer » qui n'altère pas le radical mais rajoute un « e » entre le « g » et le « a » ou le « o » de la terminaison pour conserver le phonème « ge » dans le premier cas, et transforme le « c » en « ç » pour conserver le phonème « ce » dans le second. Ces deux situations relèvent de l'orthographe lexicale et de la correspondance grapho-phonique de ces deux consonnes selon la voyelle qui les suit (cf p.14 du programme de primaire).

    Pour d'autres cas, le radical n'est pas altéré : sa voyelle « e » subie différentes accentuations, mais c'est toujours la même voyelle et le même radical. Ce qu'il y a, avec l'accentuation de cette voyelle, c'est qu'elle peut se signifier aussi bien par un accent graphique que par un doublement de la consonne qui la suit dans le cas de l'accent aigu et des consonnes « l » et « t » (on écrit, par exemple, « elle » et non « éle »). Là ce sont, à nouveau, certaines règles étranges de la correspondance graphico-phonique qui sont à l'origine de cette subdivison du premier groupe.

    Enfin il reste le cas des verbes en « -oyer » pour lesquelles le recours au « y » dans la graphie intervient pour la liaison phonétique entre les phonèmes « oi » et « er » (comme pour « noyais ») mais qui est substitué par un « i » lorsque la liaison n'est pas nécessaire (comme pour « noierait »). Connaissant peu l'histoire de notre langue, je ne saurai dire d'où vient un tel usage du « y ».

    En revanche, le verbe « aller » subit une totale altération du radical. Otachron en a donné la raison : il emprunte trois radicaux distincts issus de trois verbes latins différents (WTF !). Pour le cas des verbes « renvoyer » et « envoyer », je n'ai aucune idée de la raison de la disparition du phonème « oi » dans son radical à certain temps contrairement au verbe comme « noyer ».

    On pourrait toujours rajouter un quatrième groupe des verbes tordus, seuls de leur espèce, plutôt que de les ranger dans le troisième groupe, mais le seul rapport que je leur vois avec les autres verbes du premier groupe reste leur terminaison en « -er » et non les principes de leur conjugaison.

    Bref, comme je l’ai dit, en grammaire, l’unanimité n’a pas encore été trouvée.

    Il y a peu de chance qu'elle le soit un jour. Quand notre langue sera morte ?

    Pour le reste, ce n'est pas d'une grande importance (quoique ?); j'aurais pas mal de choses à dire mais je n'ai pas le temps d'écrire un long commentaire. Pour faire court, l'analyse lexical et les informations du dictionnaire permettent de passer de la phrase :

    • le chat mange la souris

    à une situation du genre :

    • (le : art. m. sg.) (chat : nm. sg.) (mange : vb. tr.) (la : art. f. sg.) (souris : nf. sg.)

    dans laquelle chaque mot reçoit son type grammatical (ou ses types possibles en cas d'homonymie), et ensuite les règles de la grammaire française permettent de montrer que la construction syntaxique est grammaticalement correcte et a le type d'une phrase. C'est dans cette phase qu'interviennent les problématiques algorithmiques liées à l'inférence et à la vérification de type.

    Traiter cette phase à la manière des compilateurs permettrait, par exemple, dans le cas d'une telle phrase :

    • les moldus et les cracmols ne maîtrisent pas l'art de la legilimancie

    d'inférer que les mots « moldu », « cracmol » et « legilimancie » doivent être des noms communs quand bien même ils ne se trouveraient pas dans le dictionnaire (raisonnement que tout lecteur de cette phrase, connaissant la grammaire française, fait de lui-même). Ce qui pourrait offrir la possibilité de suggérer l'ajout de ces mots avec ces catégories au dictionnaire, quand l'ajout de mot sera possible. ;-)

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Il y a un mais !

    Posté par  . En réponse à la dépêche Grammalecte, correcteur grammatical [2]. Évalué à 5.

    Fil intéressant sur la classification des verbes, en particulier celle du verbe « aller ». Le sujet dont on parle dans ce journal étant la grammaire, j'ai choisi de répondre à ce commentaire en particulier car j'y ai détecté une erreur fréquente qui passe inaperçue auprès de grammalecte. Je commencerai donc ma réponse par une petite digression, bien que je te rejoigne entièrement sur la classification de « aller » dans le troisième groupe (ainsi que sur celle de « envoyer » dans le troisième également).

    Voici la faute :

    N'oublie pas que le français reste une langue avec un historique important dont pour uniformiser les usages on a conçu l'Académie Française pour rationaliser cet historique.

    un mauvais usage du pronom relatif « dont », pourtant bien utilisé dans la phrase qui suit :

    ce qui peut faire rire étant donné la quantité d'exceptions dont bénéficient notre langue

    même si ici le verbe est mal conjugué, son sujet étant « notre langue » qui est singulier. ;-)

    Le pronom relatif « dont » introduit un groupe nominal objet, normalement introduit par la préposition « de », lorsque celui est placé avant le groupe verbal. La deuxième utilisation (celle qui est correcte) correspondant à : « notre langue bénéficie de quantité d'exceptions ». Une telle construction est souvent utilisée pour élaborer un groupe nominal sujet afin d'éviter l'usage d'une subordonnée relative (introduite par « qui »). Exemples :

    • notre langue bénéficie de quantité d'exceptions qui peuvent faire rire.
    • la quantité d'exceptions dont bénéficie notre langue peuvent faire rire.

    Revenons maintenant à la classification du verbe « aller ». Olivier a écrit dans un de ces commentaires :

    Pour ma part, je juge discutable la classification, et quand ça sort de nulle part sans explication crédible, je me demande qui, quoi, pourquoi, s’il y a une meilleure explication que « c’est comme ça ».

    et pourtant tu lui as donné le principe déterminant la classification dans le premier groupe : verbe dont l'infinitif est en « er » dont (:-P1) le radical ne subit pas d'altération lors de sa conjugaison. On peut toujours vouloir choisir un autre principe de classification (chacun est libre de choisir les principes qu'il veut après tout), mais qualifier celui-ci d'explication qui sort de nulle part est un peu fort de café, me semble-t-il.

    En ce qui concerne le verbe « aller », son radical subit une transformation dans plusieurs temps ce qui le disqualifie (selon ce principe) pour appartenir au premier groupe. Exemples : je vais, tu vas, il va, ils vont, j'irai, tu iras, il ira, nous irons, vous irez, ils iront…

    Les soient disantes irrégularités du premier groupe ne concernent jamais une altération du radical, mais des adaptations de la terminaison pour des raisons de sonorité comme le « e » dans « nous mangeons » ou le « ç » dans « nous lançons ».

    Pour ce qui est du verbe « renvoyer », la stricte parenté de conjugaison avec le verbe « voir » (en dehors du participe passé dérivé en conformité avec sa terminaison en « er ») me semble être un bon principe pour le classifier dans le troisième groupe. Prendre, par exemple, son comportement au futur (où le radical est altéré) :

    • j’enverrai
    • tu enverras
    • il enverra
    • nous enverrons
    • vous enverrez
    • ils enverront

    et le comparer à celui d'un verbe du premier groupe avec la même terminaison comme « louvoyer » :

    • je louvoierai
    • tu louvoieras
    • il louvoiera
    • nous louvoierons
    • vous louvoierez
    • ils louvoieront

    Pour répondre au principe d'Olivier qui invoquait le nombre de règles dont se sert grammalecte entre le premier et le troisième groupe. D'une manière générale, comme je l'avais déjà dit dans ton autre dépêche, je considère que les problèmes algorithmiques liés à la correction grammaticale sont analogues à ceux que l'on rencontre dans la vérification et l'inférence de types dans l'écriture de compilateur de langages de programmation. Je salue la performance de ton logiciel ainsi que ton travail mais, si les expressions régulières sont fort utiles pour de l'analyse lexicale, le choix de construire un moteur entier d'analyse grammaticale autour des expressions régulières est déjà, en soi, une option discutable2. Mais si, de plus, tu te fondes sur un tel choix pour justifier ta classification des verbes alors là je ne peux absolument plus te suivre; et il y a peu de chance que tu arrives à faire des émules chez les grammairiens (ce que je ne suis pas, mais je n'en ai jamais lu un qui classifiait « aller » dans le premier groupe).


    1. il s'agit ici d'un autre usage du pronom « dont » qui introduit un sous-ensemble d'un groupe nominal. 

    2. Voir, par exemple, l'approche des grammaires catégoriques et la façon dont leur algorithme vérifie la bonne formation de la phrase en anglais : « the bad boy made that mess ». 

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Super boulot !

    Posté par  . En réponse à la dépêche Grammalecte, correcteur grammatical [2]. Évalué à 7.

    Le problème de cette solution, c’est que tu multiplies le temps d’examen de chaque mot par le nombre de dictionnaires que tu as. Pour chaque mot, tu lances la recherche à partir de zéro dans un graphe de mots. Très coûteux en ressources donc.

    J'ai pensé aux problèmes de complexité après avoir posté mon message, mais n'y a-t-il pas non plus moyen de le résoudre en utilisant autre chose qu'une liste de dictionnaires ? Ton dictionnaire a apparemment un format binaire indexable de ton propre cru qui exige une phase de compilation. Dans ton moteur tu le charges en mémoire ou tu vas lire le dictionnaire sur le disque ? Peux-tu envisager une fusion-compilation de plusieurs dictionnaires (à la volée en fonction d'une option) avant d'entamer l'analyse proprement dite ?

    Je pose ces questions car, au-delà des néologismes et autres bizarreries, se joue la possibilité pour l'utilisateur de personnaliser son dictionnaire en fonction de ses besoins.

    L’autre problème est culturel. Vouloir refuser « les néologismes et autres bizarreries », c’est une chose; se mettre d’accord sur la place du curseur sur ces questions en est une autre. Les gens sont très divisés sur l’acceptable et l’inacceptable… Il suffit de voir tout le barouf sur “ognon”… “Ognon”, c’est un sacrilège. “Fake news”, non. Ou l’inverse. Ça dépend des personnes.

    Je prends un exemple. De nos jours, presque tout le monde ou presque écrit “décrédibiliser”… Pourtant, il existait un mot plus court que tout le monde semble avoir oublié en quelques années: “discréditer”. À mes yeux, “décrédibiliser” est néologisme superflu. Mais ça a fini par rentrer dans les dictionnaires. Ai-je eu tort de céder?

    D'où mes questions sur la possibilité d'intégrer la gestion de plusieurs dictionnaires, et les adaptations nécessaires à apporter au code. Pour l'instant, tu te retrouves à devoir arbitrer un consensus pour tous les utilisateurs, là où avec la gestion de dictionnaires multiples chacun arbitrera pour lui-même car, comme tu le dis, sur ces questions « ça dépend des personnes ».

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Super boulot !

    Posté par  . En réponse à la dépêche Grammalecte, correcteur grammatical [2]. Évalué à 4. Dernière modification le 08 juin 2017 à 21:34.

    Malheureusement, les dictionnaires n’acceptent que 2 possibilités: un mot est présent ou absent. Bref, c’est compliqué, et même si c’était faisable, ce serait un travail de titan.

    Je ne connais pas l'architecture interne de ton moteur, mais pour la présence des mots ne peux tu pas avoir deux dictionnaires (disons D1 et D2) puis, suivant une option, tu testes la présence du mot dans D1 ou bien dans un des dico de la liste [D1; D2] ? Cela demanderait trop de changement de code que le test de présence se fasse sur une liste plutôt qu'un dico fixe donné ?

    Sinon, merci pour ton logiciel que je l'utilise régulièrement via l'extension de firefox. Je vais voir pour participer à la campagne.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 2.

    Mais une question que j'avais posée est : qu'est-ce qui peut pousser un développeur à utiliser cette fonction en dehors des bornes 0 .. 63 ?

    A cette question je pourrais répondre bêtement en disant que je veux que la fonction suivante calcule le quotient de n par 2a pour toutes les valeurs de la plage des types de ses arguments.

    function quo_power2 (n, a: natural) return natural;

    Ça m'intriguait cette histoire, et je n'arrivais pas à admettre qu'un informaticien comme Xavier Leroy ait pu faire un tel choix sans une bonne raison. Pour faire de l'arithmétique entière, il y a une bibliothèque dédiée (écrite en collaboration) : Zarith qui ne fait pas partie de la distribution officielle ni de la bibliothèque standard (elle est volontairement minimaliste).

    #require "zarith";;
    #install_printer Z.pp_print;;
    
    Z.shift_right Z.one 64;;
    - : Z.t = 0
    
    Z.(shift_right (shift_left one 65) 1);;
    - : Z.t = 18446744073709551616
    
    Z.(shift_right (shift_left one 64) 128);;
    - : Z.t = 0
    
    Z.(shift_right (shift_left one 65) (-1));;
    Exception: Invalid_argument "Z.shift_right: count argument must be positive".

    Son objectif est de faire de l'arithmétique sur Z de manière efficace, et la doc de la fonction shift_right précise qu'elle a bien le comportement souhaité :

    external shift_right: t -> int -> t = shift_right@ASM
    (** Shifts to the right. 
        This is an arithmetic shift, 
        equivalent to a division by a power of 2 with rounding towards -oo.
        The second argument must be non-negative.
    *)

    Le module Int64 (et son compagnon Int32) ne doivent pas spécialement être fait pour cela :

    This module provides operations on the type int64 of signed 64-bit integers. Unlike the built-in int type, the type int64 is guaranteed to be exactly 64-bit wide on all platforms. All arithmetic operations over int64 are taken modulo 264
    
    Performance notice: values of type int64 occupy more memory space than values of type int, and arithmetic operations on int64 are generally slower than those on int. Use int64 only when the application requires exact 64-bit arithmetic.
    

    Ici comme la précision est fixe et que la performance n'est pas déjà au top, on laisse l'appelant se charger des vérifications s'il pense que cela est nécessaire, l'appelé ne fournissant que la garantie du bon résultat dans les bornes 0 .. 63 (du moins je suppute que c'est ce genre de considération qui a du influencer le choix de cette implémentation).

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 1.

    Afr, mon compilateur interne vient d'émettre un warning : risque de boucle sans fin, abort envisageable au prochain tour. ;-)

    C'est ce que j'expliquais dans un ancien post.

    Je le sais bien c'est le premier commentaire de ce sous-fil : on boucle !!! Qu'est-ce que tu n'as pas compris dans ma réponse ? Tu m'as pourtant répondu que j'avais était très clair, là c'est moi qui ne te comprends plus.

    Si OCaml disposait de la notion de sous types (contraints) alors il disposerait de deux fonctions shr.

    J'espère que tu me pardonneras la familiarité de l'expression mais j'ai envie de te répondre : « si ma tante en avait, on l'appellerait mon oncle ». J'avais pourtant précisé dans ma réponse que les systèmes de typage était une question distincte, bien qu'elle puisse être utilisée dans le cas de Ada pour traiter le problème. Mais jusqu'à preuve du contraire, un langage doit faire avec le système de type dont il dispose. À ma connaissance il n'y a aucun plan pour intégrer cette sorte de type dans le langage, ce que je peux comprendre pour des raisons théoriques liées aux fondements du langage qu'ils seraient trop longs de développer (il y a néanmoins des sous-types contraints en OCaml, mais pas de la sorte des types range comme en Ada).

    Connais tu la théorie des types ? J'avais pourtant donner un lien vers un dossier de la gazette des mathématiciens sur le sujet, l'as-tu lu ? Outre son utilité pour le typage statique des langages fonctionnelles, le système F (qui est le fondement des système de type de Haskell et OCaml) a été inventé au début des années 70 par le mathématicien et logicien français Jean-Yves Girard pour des questions liées aux fondements des mathématiques. Je cite ici sa nécrologie à la page 14 :

    En 1953, Takeuti remarquait que la logique du second ordre permettait de formuler sans axiomes toutes les mathématiques courantes, et il proposait un procédé effectif d’élimination des coupures pour étendre le théorème de Gentzen : c’est la conjecture de Takeuti. En 1965, Tait démontrait l’existence de démonstrations sans coupure pour le calcul des séquents de Takeuti, mais l’essentiel manquait, à savoir la convergence du procédé d’élimination proposé par Takeuti. C’est ce que j’ai démontré en 1970, dans l’article [1], résultat amélioré dans [2] et [3]. En fait, ce résultat se présentait comme un système de calcul fonctionnel typé, (le système F), dans lequel on pouvait définir un type nat des entiers (i.e. dont les objets sont les entiers), avec deux théorèmes principaux :

    Théorème 1
    Le procédé de calcul dans F converge (normalisation).

    Théorème 2
    Tout algorithme fonctionnel (envoyant les entiers dans les entiers) dont on peut établir la terminaison au moyen des mathématiques courantes, se représente dans F au moyen d’un objet de type nat ⇒ nat.

    Le système F est par exemple utilisé par Haskell comme représentation intermédiaire pour son compilateur. Ce système a connu depuis différentes extensions, ou il y a eu d'autres système du même genre comme la théorie des types de Per Martin-Löf, le Calcul des Constructions (CoC) à la base de Coq qui devint le Calcul des Constructions Inductives, puis on a tout récemment la théorie homotopique des types. Ces théories tournent toutes autour d'une problématique : la recherche d'un système de formalisation unifié de l'ensemble de l'édifice mathématique, ainsi que la réponse à la question : « les mathématiques sont-elles cohérentes ? ». Parce que l'on parle d'arithmétique depuis le début, mais l'arithmétique est-elle une théorie cohérente ?

    Pour revenir sur la question initiale du journal : le décalage bit à bit vers la droite. Dans un autre commentaire, tu as écris :

    Haskel, Python, Ada, Eiffel le proposent. D'autres langages de haut niveau ne font rien de plus que le jeu d'instruction X86 et je trouve que c'est une faiblesse (générateur de bugs).

    Premièrement ce que fait Haskell, la bibliothèque standard OCaml aurait pu tout aussi bien le faire : je l'ai expliqué précédemment; cela n'a pas été l'option retenue (j'ignore, néanmoins, les raisons qui ont déterminé un tel choix). Ce n'est pas lié au possibilité du langage mais à un choix d'implémentation pour la bibliothèque standard fournie avec le compilateur. Mais ce n'est pas la seule existante, elle a des concurrentes certains développeurs ne la jugeant pas assez fournie.

    Deuxièmement mettre Python dans la liste sur des questions de sécurités de code : c'est une blague ou tu es sérieux ?

    Troisièmement, vu que tu viens de rajouter une exigence à ton cahier des charges : ne pas avoir de types cycliques pour le paramètre déterminant le degré du décalage, tu viens de les perdre tous sauf Ada. La liste des langages qui trouve grâce à tes yeux s'amenuise de plus en plus au fur et à mesure que progresse la discussion. ;-)

    Pour le cas de Haskell, je l'ai déjà illustré. Pour celui de Eiffel, si je lis la documentation

    infix "|>>" (s: INTEGER_8): INTEGER_64
        Shift by s positions right (sign bit copied) bits falling off the end are lost.
    bit_shift_right (s: INTEGER_8): INTEGER_64
        Shift by s positions right (sign bit copied) bits falling off the end are lost.

    Déjà le paramètre est sur 8 bit, donc ton exercice n'est pas réalisable en Eiffel avec cette version de shift_right. Et si je lis la documentation sur les INTEGER_8, dans le résumé je vois : 8 bits signed integer. J'ai comme le pressentiment qu'il est cyclique lui aussi : si un développeur Eiffel pouvait confirmer mon intuition ?

    Et pour le langage de départ du projet de tes élèves, FreePascal, outre le comportement du shr inattendu, il me semble bien d'après cette documentation que le type en question est lui aussi cyclique :

    function isBitSet(AValue, ABitNumber:integer):boolean;
    begin
       result:=odd(AValue shr ABitNumber);
    end;

    Ai-je raison de supposer que le type integer est cyclique en Pascal ?

    Comme de tout le fil de discussion et de tous les commentaires je suis le seul à avoir pointé du doigt l'importance de la nature du type de ce paramètre, je suis au regret de devoir émettre une nouvelle hypothèse qui me chagrine en espérant me tromper. Le « bug » n'était pas anticipé et a été découvert par hasard, et malgré son apparente solution tu en es au même point d'incompréhension que tes élèves : la source fondamentale du problème c'est la différence de géométrie entre un tore et un cylindre. ;-)

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 2.

    De rien. Je suis content de voir qu'il y a au moins une personne qui apprécie mon humour.

    Mais cette lecture peut au moins répondre partiellement à la question : que peut-on vouloir modéliser avec cela ? Une piste serait alors la modélisation de l'Odysée d'Ulysse dans une vision Homérique où il n'aurait fait que voyager sur un beignet. Les grecs anciens ayant été le premier peuple à émettre l'hypothèse que la terre ne serait ni plate ni sphérique mais aurait la forme d'un beignet ! :-P

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 1. Dernière modification le 20 mai 2017 à 15:29.

    Mais une question que j'avais posée est : qu'est-ce qui peut pousser un développeur à utiliser cette fonction en dehors des bornes 0 .. 63 ?

    Là tu veux dire que tu trouves rare ce genre de situation ?

    la majorité des codes l'utilisant se retrouveraient pénalisés d'un test inutile sur X86

    Et là tu veux dire que finalement tu trouves fréquente ce genre de situation ? J'avoue que suis un peu perdu dans ce que tu me dis.

    J'émettais bien l'hypothèse que les situation où on avait besoin de sortir de ces bornes étaient rares. En conséquence, la grande majorité de codes utilisant shift_right se retrouveraient pénalisés d'un test inutile sur X86 si les implémenteurs de langage haut niveau choisissaient tous ton approche, pour la simple est bonne raison qu'il ne sortiront jamais de ces bornes et que ce test dynamique s'avérait inutile pour eux. Certains langages, dont OCaml fait partie, semblent avoir fait le choix de ne garantir le bon comportement que sur l'intervalle O .. 63 pour des raisons tout à fait légitimes d'efficacité et de le documenter. Ainsi les cas exceptionnels qui ont besoin de sortir de ces bornes doivent coder leur propre fonction avec un test sur la valeur de l'entrée. C'est un choix qui me semblent tout à fait convenable d'un point de vue pragmatique. Tu dois bien reconnaître que ton projet est un cas bien particulier à but pédagogique que des programmeurs réaliseront peut dans la réalité. Rust va même jusqu'à refuser de compiler s'il détecte statiquement que l'on sort de ces bornes.

    Une approche peut être plus mixte est celle de Haskell, qui se comprend et se tient aussi : mais tout cela reste une question de choix. Je suis allé voir le code qui nous intéresse et l'on trouve :

    (W64# x#) `shift` (I# i#)
            | isTrue# (i# >=# 0#)  = W64# (x# `shiftL#` i#)
            | otherwise            = W64# (x# `shiftRL#` negateInt# i#)
    (W64# x#) `shiftL`       (I# i#) = W64# (x# `shiftL#` i#)
    (W64# x#) `unsafeShiftL` (I# i#) = W64# (x# `uncheckedShiftL#` i#)
    (W64# x#) `shiftR`       (I# i#) = W64# (x# `shiftRL#` i#)
    (W64# x#) `unsafeShiftR` (I# i#) = W64# (x# `uncheckedShiftRL#` i#)

    Puis pour shiftL et shiftRl :

    -- Wrappers for the shift operations.  The uncheckedShift# family are
    -- undefined when the amount being shifted by is greater than the size
    -- in bits of Int#, so these wrappers perform a check and return
    -- either zero or -1 appropriately.
    --
    -- Note that these wrappers still produce undefined results when the
    -- second argument (the shift amount) is negative.
    
    -- | Shift the argument left by the specified number of bits
    -- (which must be non-negative).
    shiftL# :: Word# -> Int# -> Word#
    a `shiftL#` b   | isTrue# (b >=# WORD_SIZE_IN_BITS#) = 0##
                    | otherwise                          = a `uncheckedShiftL#` b
    
    -- | Shift the argument right by the specified number of bits
    -- (which must be non-negative).
    -- The "RL" means "right, logical" (as opposed to RA for arithmetic)
    -- (although an arithmetic right shift wouldn't make sense for Word#)
    shiftRL# :: Word# -> Int# -> Word#
    a `shiftRL#` b  | isTrue# (b >=# WORD_SIZE_IN_BITS#) = 0##
                    | otherwise                          = a `uncheckedShiftRL#` b

    Ce qui revient peu ou prou à implémenter les fonctions << et >> comme je l'ai fait plus haut en OCaml à partir des versions fournies par la bibliothèque standard dans le module Int64. Les implémenteurs de la bibliothèque standard OCaml n'ont pas choisi cette approche, laissant le soin aux développeurs qui en ressentent le besoin de le faire eux même.

    Cela étant il reste la question de la circularité du second argument, qui ne pose pas de problème en ADA, mais qui en pose un en Haskell :

    >import Data.Word
    >import Data.Bits
    >(1 :: Word64) `shiftR` 64
    0
    >(1 :: Word64) `shiftR` (maxBound :: Int)
    0
    >(1 :: Word64) `shiftR` (maxBound :: Int) + 1
    1

    Raison pour laquelle j'avais posé la question qui, elle aussi, n'était pas dénuée de fondements. ;-)

    Et puis bon, c'est quand même étrange de fournir, à haut niveau, un opérateur qui fournit le même quotient par 2^64 que par 1 dans un langage de haut niveau sous prétexte que certains processeurs ont ce comportement pour de simples raisons d'optimisation.

    J'espère t'avoir fait comprendre que, bien que le comportement puissent apparaître étrange lorsqu'on l'ignore, ce n'était pas un choix dénué de fondements ni sans justifications tout à fait recevables. Le seul reproche que l'on peut faire à freePascal est de ne pas le documenter mais non d'avoir un tel comportement.

    Sinon toujours en étant taquin, en poussant ton principe à l'extrême, je pourrais dire : un langage qui a besoin de tests unitaires n'est pas un langage haut niveau digne de ce nom. :-P

    De tels langages existent et comme je ne suis pas sectaire je te propose la méthode B présentée au Collège de France par son concepteur.

    Cette présentation est celle d’un chercheur vieillissant qui porte un regard historique sur les trente dernières années de son travail.

    Il y a deux sortes de chercheurs : les prolifiques et les monomaniaques. Je fais partie de la seconde catégorie, car j'ai toujours pratiqué le même genre d’investigations, à savoir la spécification et la construction vérifiée de systèmes informatisés.

    Ce travail, autant théorique que pratique, s’est concrétisé au cours de toutes ces années dans trois formalismes voisins : Z, B et Event-B (dont je ne suis pas, loin de là, le seul contributeur). Je vais tenter d’expliciter comment les idées que contiennent ces formalismes et les outils correspondants ont lentement émergés de façon parfois erratique.

    Je tenterai aussi de préciser les multiples influences qui ont participé à cette évolution. En particulier, je montrerai comment plusieurs réalisations industrielles ont permis de progresser dans ce domaine. Mais je soulignerai aussi les échecs et parfois les rejets de la part de communautés tant universitaires qu’industrielles.

    Pour finir, je proposerai quelques réflexions et approches pour le financement de recherches telles que celle-ci.

    Présentation dont j'extrais deux diapos :

    la RATP décide de supprimer les tests unitaires et d'intégration

    Octobre 98 : lancement de la ligne 14

    Depuis lors pas de problèmes avec le logiciel développé avec [soit 17 ans plus tard, et il tourne, tourne, tourne…]

    pour remplacer l'ancienne méthodologie avec tests unitaires par celle-ci :

    86.000 lignes en ADA ont été produites automatiquement

    27.800 preuves ont été faites

    92% ont été prouvés automatiquement par l'Atelier B

    Coût des preuves interactives : 7 hommes-mois

    Les preuves interactives sont moins chères que les tests

    Tu vois ADA lui aussi n'est pas assez « haut niveau » finalement. En fait Ada est à la méthode B ce que OCaml est à Coq : le langage dans lequel est écrit son noyau ainsi que le langage cible vers lequel il « compile ». Coq qui a servi, par exemple, à ecrire un compilateur C certifié correct. Ce sont là des exemples de ce que peut faire la rigueur de la formalisation mathématique pour garantir l'absence de bug dans un logiciel, à condition d'être effectuée avec les outils et les langages adéquats. ;-)

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 2.

    J'ai d'ailleurs une autre question : en ADA le type natural est-il lui aussi cyclique ou, sinon, que se passe-t-il lorsque l'on arrive aux bornes ? Dans plein de langage, dont OCaml, le type du second paramètre est lui aussi cyclique (le type int c'est Z/2^63Z en 64 bits) ce qui ne ferait que repousser le comportement observé de manière tout aussi étrange lui aussi.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 2. Dernière modification le 19 mai 2017 à 18:10.

    Pour ce que doit faire le shift_right, on est d'accord : il décale à droite et remplace les trous par des zéros. Mais une question que j'avais posée est : qu'est-ce qui peut pousser un développeur à utiliser cette fonction en dehors des bornes 0 .. 63 ? C'est pour cela que j'avais écrit qu'elle ne faisait vraiment sens que sur cette intervalle. Dans quel contexte va ton réellement lui passer les valeurs 64, 65 ou tout autre supérieure ? Et cela ce n'est pas sans incidence pour un implémenteur de langage haut niveau. Comme tu l'as montré pour ADA : si on évite les valeurs supérieures à 63, on évite un test de comparaison à chaque exécution sur une architecture X86. Quelle intérêt un code pourrait avoir, sur une telle instruction, de se rendre dans un domaine où la sortie vaut toujours 0 ? Et je pense que la raison qui à présider au choix de laisser le comportement non défini en dehors de ces bornes sont des raisons de performances générales : la majorité des codes l'utilisant se retrouveraient pénalisés d'un test inutile sur X86. C'était là le fruit de mes « spéculations », comme celles de Def. Et c'est aussi ce que dit wikipédia :

    This helps allow C compilers to emit efficient code for various platforms by allowing direct use of the native shift instructions which have differing behavior.

    Ensuite sur ce que fait X86, je n'ai pas dit que c'était délibéré de leur part (bien que ma formulation pouvait laisser penser le contraire) mais je ne faisais que décrire, en me basant sur son comportement, la structure mathématique qui lui correspondait : un opérateur sur un tore, son domaine se ramenant de fait à Z/2^64Z x Z/64Z. Que peut-il servir à modéliser en pratique dans le quotidien d'un programmeur, j'en sais foutre rien et je m'en fout un peu à vrai dire. Mais c'est plus drôle qu'une fonction stationnaire, et c'est joli un donut ! :-P

    Quoi qu'il en soit, pour un langage haut niveau qui reproduit l'instruction machine, le développeur ne peut pas s'appuyer sur le comportement de shr sur X86 s'il veut un tel comportement, mais le coder lui-même s'il veut un code portable. Comme il doit le coder lui-même s'il veut que la sortie soit constamment égale à 0.

    let ( >> ) m n = match n with
    | n when n > 63 -> Int64.zero
    | _ -> Int64.shift_right m n
    
    1L >> 64;;
    - : int64 = 0L
    
    1L >> 65;;
    - : int64 = 0L

    Pour ce qui est de ton autre question pour OCaml sur PowerPC, je suppose que la réponse est : la sortie est stationnairement nulle à partir de 64. Ce qui est sans doute aussi le cas en C ou C++. Mais je n'ai pas de telle machine à disposition, ni de ARM, pour vérifier.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 2.

    Je te rejoins quasiment en tout point. Sauf sur le point clé suivant: […]

    Effectivement, c'est sur ce point que l'on diverge. C'est lorsque tu écris : « [elle] ne devrait répondre qu'au seul problème du quotient d'un entier machine entre 0 et 2n - 1 par une puissance positive quelconque de 2 » en parlant de la primitive shift_right. Pour moi, elle ne devrait rien être, mais elle est ce que l'implémenteur a décidé qu'elle serait. C'est tout le problème de la spécification d'un code. C'est pour cela que j'avais écrit :

    En conséquence, la seule chose à faire si l'on veut savoir ce que fait une fonction, c'est d'aller lire la doc : on ne peut pas se fier uniquement à son type ni à ses attentes. Et le seul moyen de vérifier qu'elle se comporte exactement comme le spécifie la doc, c'est d'aller lire le code d'où la condition sine qua non que celui-ci soit publiquement accessible. Voilà une leçon que pourront retenir tes étudiants de cet exercice.

    C'est un peu comme Hilbert qui disait qu'en géométrie on s'en fout des noms point, droite ou plan et qu'on pourrait les remplacer par chope de bière, chaise et table : ce qui compte c'est l'axiomatique des structures. Dans toute cette histoire, moi ce que je vois c'est que certains langages ne te fournissent pas de base l'axiomatique que tu souhaiterais. Ce à quoi je te réponds : ils te donnent néanmoins les moyens de construire la structure que tu désires. D'ailleurs au sujet de ADA, je suis allé voir la documentation est le moins que l'on puisse dire c'est que ni le type, ni son complément dans la documentation ne permet de savoir c'est que fait cette fonction shift_right. Même grâce au complément en langue anglaise, je trouve que l'on a là une sous-spécification de son comportement. Au moins, dans certains langages qui ne font pas ce que tu souhaites, avec la documentation on sait ce qu'elle doit faire.

    Au fond ce que je vois, c'est qu'on a un opérateur qui agit sur un cylindre : produit cartésien d'un anneau Z/nZ avec un domaine fini. Toi tu veux que l'on prolonge le cylindre en saturant sur sa valeur au bord (ARM), d'autres recollent les bouts et opèrent sur un tore (X86). Ce qui compte surtout c'est qu'il soit possible de faire des découpages et des collages pour construire la structure que l'on souhaite, et cela tous les langages le permettent. Le rôle d'un langage de haut niveau c'est de fournir des moyens plus abstrait que l'assembleur pour effectuer ces constructions puis de passer la main au compilateur pour traduire le tout en code machine. Apprendre un langage donné consiste essentiellement à apprendre les méthodes de construction qu'il fournit pour définir des structures ainsi que les moyens pour opérer sur celles-ci.

    Ce que tes étudiants ont expérimenté c'est qu'un tore est cyclique sur ces deux dimensions et qu'il n'a pas du tout la même géométrie qu'un cylindre. Ce qui me rappelle un épisode des Simpson dans lequel Stephen Hawking était très intéressé par la théorie d'Homer selon laquelle l'Univers avait la forme d'un Donuts. :-P

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Du haut niveau pour gérer correctement du bas niveau

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 7.

    Je me permets de concentrer dans ce commentaire ma réponse à celui-ci ainsi qu'à cet autre commentaire, étant donné que tu y reprends les mêmes idées. Tu as été clair malgré l'heure tardive, j'espère pouvoir faire de même en cette heure plus matinale.

    Il me semble que dans ton approche de la question, tu mélanges plusieurs problématiques. Dans l'exemple que tu donnes ici, tu montres surtout comment un système de type avancé (ici une forme restreinte de type dépendant) permet d'être plus précis sur la spécification d'un code et comment un compilateur peut en tirer partie pour générer un code optimisé (ici en supprimant un test de comparaison à l'exécution rendu inutile par ton type amount). Cela rejoint un exemple que j'avais donné dans la dernière dépêche sur Haskell, où je montrais comment utiliser les GADT (types de données algébriques généralisés) pour exprimer la proposition : « tout arbre binaire parfait non vide a une racine ». Ce qui permettait de coder la fonction qui extrait cette racine sans que le code généré par le compilateur ait à vérifier à l'exécution que l'arbre était non vide (c'était déjà spécifié dans le type de la fonction).

    Revenons à présent au sujet précis du journal : le décalage à droite bit à bit. Dans un autre commentaire, tu précises à bon droit que l'arithmétique modulaire est la base de tous les processeurs courants et dans le cas présent on fait de l'arithmétique dans l'anneau Z/nZ avec n = 2^64. Se pose alors la question que doit faire cette fonction de décalage à droite ? et tu réponds toi même : « [elle] ne devrait répondre qu'au seul problème du quotient d'un entier machine entre 0 et 2n - 1 par une puissance positive quelconque de 2 ». Ce à quoi je te répondrai : l'architecture X86 fait cela en restant dans le cadre de l'arithmétique modulaire, et ne la mélange pas avec de l'arithmétique sur les entiers. En effet prenons le type de cette fonction : function my_shr (u : unsigned_64; a : natural) return unsigned_64. Elle prend en paramètre un entier non signé sur 64 bits, un entier naturel et renvoie un entier non signé sur 64 bits. Or pour opérer au sein de l'anneau sus-mentionné, elle doit donc associer un élément de cette anneau au paramètre a : natural, puis renvoyer ensuite le quotient d'une division euclidienne effectuée au sein de l'anneau. Les processeurs X86 on fait le choix de prendre l'élément 2 ^ (a % 64), ce qui peut sembler assez « naturel » lorsque l'on pratique l'arithmétique modulaire. Exemple en OCaml sur mon X86 :

    Int64.(shift_right 4L 0);;
    - : int64 = 4L
    
    Int64.(shift_right 4L 1);;
    - : int64 = 2L
    
    Int64.(shift_right 4L 64);;
    - : int64 = 4L
    
    Int64.(shift_right 4L 65);;
    - : int64 = 2L

    En revanche, de ce que j'ai compris, l'architecture ARM ne voit pas cela du tout comme une opération d'arithmétique modulaire, mais semble considérer une telle donnée (un entier non signé sur 64 bit) comme un suite finie de 0 et de 1 ou plutôt comme une suite stationnaire de valeur nulle à partir du rang 64 et si tu lui donne la suite u(n) elle te renvoie la suite u(n+a). Ce qui semble être le comportement que tu souhaiterais, mais ce n'est pas du tout le point de vue de l'arithmétique modulaire. Autrement dit, elle voit un entier de 64 bit comme un entier naturel compris entre 0 et 2^64 - 1 représenté en base 2, effectue une division euclidienne par une puissance de 2 et opère donc sur l'ensemble des entiers naturels.

    Viens maintenant le problème des langages compilés et de la spécification qu'ils donnent à une telle primitive. Ils pourraient tout à fait faire un choix strict et défini en optant pour la vision modulaire à la X86 ou la vision entière à la ARM. La plupart on choisit d'utiliser pour chaque architecture la primitive correspondante du processeur et elle n'est donc spécifiée et définie que sur le domaine où elles coïncident, à savoir 0≤ a < 64. Si le programmeur veut une fonction plus fortement spécifiée, alors il n'a qu'à la coder lui-même.

    Tu concluais ton commentaire réponse par : « c'est pour ça que j'adore l'Ada, vous l'aurez remarqué :) », je terminerai le mien par j'adore le lamba-calcul typé et rien de plus normal pour le mathématicien et logicien que je suis :) Le lamba-calcul typé (dont font partie les langages comme Haskell, OCaml ou Coq) a pour principe fondamental la correspondance preuve-programme : une programme est la preuve d'un théorème dont l'énoncé est le type ! \o/

    Ce qui donne le tableau suivant :

    Informatique Mathématiques
    Type Formule
    Programme Preuve
    Primitive système Axiome
    Fonction de A vers B Preuve de « A implique B »
    Paire de A et B Preuve de « A et B »
    Type somme sur A et B Preuve de « A ou B »
    Interpréteur Théorème de correction
    Décompilateur Théorème de complétude

    Si l'on prend le langage qui a le système de type le plus sophistiqué (Coq), je te laisse deviner ce que fait une fonction dont le type est « pour tout (n: nat), il existe (p:nat) tel n ≤ p et p soit premier » si on lui passe un entier en entrée. En Coq, cela pourrait se définir ainsi :

    Definition greater_prime (n:nat) :=
     {p :nat | n<=p /\ prime p}.
    
    Theorem ma_fonction n : greater_prime n.
    Proof.
    (* la preuve *)
    Qed.

    Pas besoin d'aller lire la doc pour savoir ce que fait la fonction, la lecture de son type suffit à cela. ;-)

    Au final si j'étais un peu taquin, en se basant sur la popularité des langages de programmation je dirais qu'à l'heure actuelle la programmation consiste, la plupart du temps, dans l'art de faire des mathématiques comme un goret dans des langages atrophiés. En conséquence, la seule chose à faire si l'on veut savoir ce que fait une fonction, c'est d'aller lire la doc : on ne peut pas se fier uniquement à son type ni à ses attentes. Et le seul moyen de vérifier qu'elle se comporte exactement comme le spécifie la doc, c'est d'aller lire le code d'où la condition sine qua non que celui-ci soit publiquement accessible. Voilà une leçon que pourront retenir tes étudiants de cet exercice.

    Comme tu enseignes les mathématiques, si le sujet t'intéresse il y a un dossier sympa sur le sujet dans la gazette des mathématiciens d'octobre 2014 : théories des types et mathématiques certifiées, et la théorie homotopique des types pousse encore plus loin la correspondance que j'ai signalée plus haut et fournit des fondements élégants à l'ensemble de l'édifice mathématique.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Primitive en C pour OCaml

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 4.

    Je me suis précipité dans mon code, celui-ci est plus « naturel » :

    let rec ( << ) m n = 
     if n < 0 then m >> (~- n)
     else if n >= 64 then Int64.zero
     else Int64.shift_left m n
    and ( >> ) m n =
      if n < 0 then m << (~- n)
      else if n >= 64 then (if Int64.compare m Int64.zero < 0 then Int64.minus_one else Int64.zero)
      else Int64.shift_right m n;;
    val ( << ) : int64 -> int -> int64 = <fun>
    val ( >> ) : int64 -> int -> int64 = <fun>

    et on a une certaine cohérence :

    -16L << 60;;
    - : int64 = 0L
    
    -1L << 64;;
    - : int64 = 0L
    
    -16L >> 60;;
    - : int64 = -1L
    
    -1L >> 64;;
    - : int64 = -1L

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Primitive en C pour OCaml

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 4.

    Merci beaucoup pour toutes ces précisions, je comprends mieux ce qui se passe (ainsi que l'organisation interne du compilateur).

    Et ça peut expliquer pourquoi une sémantique sous-spécifiée a été choisie (mais je spécule) : les shifts sont traduits vers du code très efficace, mais leurs sémantiques côté machine change selon les plateformes.

    En spéculant aussi, j'en arrive à la même conclusion. D'appelant en appelé, on finit toujours par appeler en toute fin une instruction machine : autant prendre le plus dénominateur commun des architectures. Cela permet d'avoir le code le plus efficace sur toute les architectures, et si l'appelant veut une spécification plus large, il la code lui même, ce n'est pas bien compliqué.

    let rec ( << ) m n = 
     if n < 0 then m >> (~- n)
     else if n >= 64 then Int64.minus_one
     else Int64.shift_left m n
    and ( >> ) m n =
      if n < 0 then m << (~- n)
      else if n >= 64 then Int64.zero
      else Int64.shift_right m n;;
    val ( << ) : int64 -> int -> int64 = <fun>
    val ( >> ) : int64 -> int -> int64 = <fun>
    
    1L >> 63;;
    - : int64 = 0L
    
    1L >> 64;;
    - : int64 = 0L
    
    1L >> (-64);;
    - : int64 = -1L
    
    1L >> (-63);;
    - : int64 = -9223372036854775808L

    Je pense que ce doit être aussi la raison pour laquelle en C ou C++ le comportement n'est pas spécifié. Ce sont des instructions très bas niveau, cela permet d'avoir l'instruction la plus efficace sur chaque architecture et il est de la responsabilité de l'appelant de vérifier que le second paramètre se trouve bien dans les bornes où la fonction fait sens sans ambiguïté. Dans des langages haut niveau, on peut même se demander si le choix de la structure de données est le plus adapter au problème si l'on se retrouve à devoir gérer des cas en dehors des bornes « naturelles ».

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Primitive en C pour OCaml

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 4.

    Je suppose que les fonctions asr et lsr sont du même acabit

    Tu supposes bien, elles sont définies dans le module Pervasives :

    external ( lsl ) : int -> int -> int = "%lslint"
    external ( lsr ) : int -> int -> int = "%lsrint"
    external ( asr ) : int -> int -> int = "%asrint"

    et la doc précise bien que le comportement est non spécifié :

    val (lsl) : int -> int -> int
      n lsl m shifts n to the left by m bits. The result is unspecified if m < 0 or m >= bitsize, where bitsize is 32 on a 32-bit platform and 64 on a 64-bit platform.
    
    val (lsr) : int -> int -> int
      n lsr m shifts n to the right by m bits. This is a logical shift: zeroes are inserted regardless of the sign of n. The result is unspecified if m < 0 or m >= bitsize.
    
    val (asr) : int -> int -> int
      n asr m shifts n to the right by m bits. This is an arithmetic shift: the sign bit of n is replicated. The result is unspecified if m < 0 or m >= bitsize.
    

    Reste la question : pourquoi avoir suivi le comportement du C au lieu de définir le résultat proprement ? Je n'en ai aucune idée.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Quelques autres

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 6.

    Comme pour les autres, c'est dans la doc :

    Shifting by the number of bits in a native integer (or more) is zero, except when the "overshift" is right shifting a negative value under use integer , in which case the result is -1 (arithmetic shift).

    Until now negative shifting and overshifting have been undefined because they have relied on whatever the C implementation happens to do. For example, for the overshift a common C behavior is "modulo shift":

    1 >> 64 == 1 >> (64 % 64) == 1 >> 0 == 1  # Common C behavior.
    # And the same for <<, while Perl now produces 0 for both.

    Now these behaviors are well-defined under Perl, regardless of what the underlying C implementation does.

    Jusqu'à la 5.2, Perl se reposait sur l'implémentation en C et le comportement était indéfini; depuis la 5.4, le comportement est bien défini.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • # Primitive en C pour OCaml

    Posté par  . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 6.

    En regardant le fichier d'implémentation et l'interface du module Int64, on tombe sur :

    external shift_right : int64 -> int -> int64 = "%int64_asr"
    external shift_right_logical : int64 -> int -> int64 = "%int64_lsr"

    ce qui signifie que les fonctions sont des primitives codées en C (je n'ai pas trouvé le code C correspondant). Je suppose que la première doit correspondre à un décalage arithmétique et la seconde à un décalage logique. Ne connaissant pas la norme du C, mais elle doit rejoindre celle du C++ là-dessus, si c'est implementation defined alors le comportement des fonctions OCaml dépend du compilateur C utilisé et donc il paraît normal que le comportement soit non spécifié.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Abstention abstention ...

    Posté par  . En réponse au journal Résultats des elections, qui est le vrai vainqueur ?. Évalué à 5.

    Est-ce mieux, moins bien ? Diffficile à dire. Et paradoxalement, tu critiques le résultat de notre type de scrutin, alors que dans le cas présent, c'est plus un "second choix" qui a été élu. Macron a profité du vote utile au premier tour, et au second tour il a rassemblé tous ceux qui le préféraient à Le Pen.

    La question n'est pas de savoir si dans certaines situations notre mode de scrutin finit par désigner tout de même un candidat de Condorcet, mais qu'un tel candidat puisse passer à la trappe. Le problème est même plus profond : il n'existe pas de méthode pour agréger les préférences individuelles et en sortir une « unique préférence collective » (l'énoncé est volontairement flou, pour plus de précision voir le théorème d'Arrow ou sa variante de Gibbard-Satterthwaite).

    Le problème de notre système, que l'on retrouve dans les discussions de ce journal, et qu'il incite au vote utile (on n'exprime pas réellement sa préférence maximale, mais on peut être tenter de « calculer ») et surtout qu'il mène à des situations où un parti comme le FN, qui n'a aucune chance d'être élu, se retrouve au second tour. Il existe des méthodes, certes « non parfaites » (cf. impossibilité ci-dessus), à un seul tour qui possède bien moins de défauts (voir par exemple les trois articles sur Images des Maths dans mon premier message de ce fil).

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Première historique..

    Posté par  . En réponse au journal MacronLeaks est tombé dans le pot de miel tendu par En Marche!. Évalué à 5.

    rappeler aux enfant que la drogue c'est mal, quand même

    On n'a pas du assez te le dire qu'en tu en étais un. :-P

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: imprécisions et mauvais conseils

    Posté par  . En réponse au journal Comment je suis passé d'Ubuntu à Debian Sid. Évalué à 4.

    D'où le pinning en ayant les dépôts de Sid dans le sources.list, avec priorité pour Testing, et on vise explicitement Sid avec l'option -t sid pour le paquet en question dès qu'il est dispo : pas besoin d'attendre qu'il arrive dans testing.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Résultats alternatifs

    Posté par  . En réponse au journal Résultats des elections, qui est le vrai vainqueur ?. Évalué à 2.

    Pour ma part j'ai participé à l'expérience voter autrement, mais les résultats ne seront diffusées qu'à l'issue du second tour des législatives.

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Abstention abstention ...

    Posté par  . En réponse au journal Résultats des elections, qui est le vrai vainqueur ?. Évalué à 3.

    La discussion portait sur les modes de scrutin et non sur l'organisation politiques des pays. Et je maintiens mon avis sur le scrutin majoritaire uninominale à deux tours. Mais pour comprendre le problème, et exprimer un avis un minimum avisé sur le sujet, encore faut-il au moins faire l'effort de lire les liens de mon message (ne serait-ce que pour savoir de quoi l'on parle).

    Par exemple pour reprendre la conclusion du message auquel je répondais :

    Et pour revenir à ta remarque en début de paragraphe, le gars dont on parle a été premier à chaque tour. Question légitimité ça me parait difficile à remettre en cause.

    On peut sans difficulté imaginer une situation où trois options A, B et C sont présentées aux électeurs. Les préférences du corps électoral seraient divisées en trois groupes :

    • A > C > B : 40 % (A est préféré à C qui est préféré à B) ;
    • B > C > A : 35 % (B est préféré à C …) ;
    • C > A > B : 25 %.

    Avec une telle répartition du corps électoral, si chaque électeur dans notre système choisit l'électeur qu'il préfère, on a un premier tour avec A à 40 %, B à 35 % et C à 25 %; puis un second tour qui donne A victorieux avec 65 % (40 + 25) face à B avec 35%. Il est largement premier aux deux tours et donc « question légitimité, ça paraît difficile à remettre en cause ».

    Pourtant, le candidat C (éliminé au premier tour) gagnerait en duel face à chacun des deux autres : 60 % (35 + 25) face à A et 65 % (40 + 25) face à B; C est ce que l'on appelle un candidat de Condorcet. Alors lequel de A et C est le plus légitime selon toi ?

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: Cell-eux qui ne sont pas comptées...

    Posté par  . En réponse au journal Résultats des elections, qui est le vrai vainqueur ?. Évalué à 2.

    Si on se fit à une étude INSEE de mars 2017 ainsi qu'aux résultats, on a ces chiffres :

    Électorat potentiel (population française en âge de voter) 53 689 151 100,00%
    Non inscrits 6 120 563 11,40%
    Abstentions 12 101 416 22,54%
    Blancs et Nuls 4 069 256 7,58%
    M. Emmanuel MACRON 20 753 798 38,66%
    Mme Marine LE PEN 10 644 118 19,83%

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

  • [^] # Re: HTTP remplacent ?

    Posté par  . En réponse au journal Debian va débrancher ses dépôts FTP. Évalué à 3. Dernière modification le 10 mai 2017 à 12:49.

    Elle est intéressante votre discussions. En cherchant un peu, je suis tombé sur une étude (ancienne vu le sujet, elle date de 2008) qui testait la sécurité de différents gestionnaires de paquets et les méthodes de distribution : A Look In the Mirror: Attacks on Package Managers. Je n'ai pas eu le temps de la lire en détail, mais en conclusion il pointe bien un problème sur le HTTP / HTTPS :

    If the package manager supports HTTPS and it correctly checks certificates, the distribution can set up
    repositories or mirrors that support HTTPS transfers. This will not protect against a malicious mirror, but will prevent a man-in-the-middle attack from an outsider.

    Apparemment, l'étude consistait à montrer comment on pouvait créer un miroir malicieux. Si quelqu'un a le courage de regarder plus en profondeur l'étude et voir si certains éléments sont toujours d'actualité…

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.