Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

Pas de bol pour COBOL : Sophus, ça fuse !

Une fonction associe à une variable x une autre variable y ; lorsqu’un groupe opère sur un ensemble, il transforme les nombres. Il semble qu’en algorithmique, la seconde notion soit plus naturelle que la première

Article mis en ligne le 11 octobre 2014
dernière modification le 27 avril 2021

par Alain Busser, Florian Tobé

Cet article peut être librement diffusé à l’identique dans la limite d’une utilisation non commerciale suivant la licence CC-by-nc-nd (http://creativecommons.org/licenses/by-nc-nd/3.0/fr/)

Pour le prof, les deux phrases suivantes sont équivalentes :

  • Mettre x+1 dans x
  • Augmenter x de 1

Mais pas pour les élèves, en terme de facilité d’abstraction. Ceux-ci préfèrent souvent transformer les nombres in situ plutôt que faire des allers-retours entre lecture et écriture.

Comment tout a commencé

Pour finir l’année civile, et pour préparer le bac blanc avec une petite révision sur la loi binomiale [1], l’un de nous a proposé le TP suivant en terminale STI2D :

le TP révélateur
l’énoncé du TP ; durée prévue : 1 heure en terminale (révision) (en réalité il en faut plus)

L’outil de programmation étant celui-ci [2] :

outil de programmation CoffeeScript
Double-cliquer sur « alcoffeethmique.html » pour lancer l’outil d’algorithmique

Les abréviations suivantes ont été utilisées :

  • bI pour « borne inférieure »
  • bS pour « borne supérieure »
  • et IF pour « intervalle de fluctuation »

L’écriture [bI,bS] désigne en CoffeeScript, un tableau de deux nombres et non l’intervalle délimité par ces nombres.

Voici l’attendu en CoffeeScript [3] :

  1. IF = (N,p) ->
  2.     [bI,bS] = [0,N]
  3.     somme = 0
  4.     until somme >= 0.025
  5.         somme = somme + binomiale(N,p,bI)
  6.         bI = bI + 1
  7.     bI = bI - 1
  8.     somme = 0
  9.     until somme >= 0.025
  10.         somme = somme + binomiale(N,p,bS)
  11.         bS = bS - 1
  12.     bS = bS + 1
  13.     [bI,bS]

Télécharger

Or nous avons constaté que la phrase « ajouter à somme la probabilité d’avoir bI succès » était très difficile à programmer que ce soit sur la calculatrice ou avec CoffeeScript ; idem pour la phrase suivante « incrémenter bI » :

  • Plusieurs élèves ont tenté d’écrire directement dans CoffeeScript le code ajouter bI, 1 qui leur paraissait similaire à la syntaxe habituelle de l’outil, et plus naturelle (selon leurs dires) que bI = bI + 1
  • La plupart des élèves ont admis que l’écriture bI++ leur paraissait plus naturelle (!) que bI = bI + 1
  • Quelques-uns, victimes de leur connaissance de Python [4], ont même tenté, dans succès, un from bI import 1
  • L’un d’eux, ne sachant pas comment on dit « jusque » en anglais, a utilisé Google pour faire son programme.

Un des élèves a même produit l’ébauche de ceci (corrigé par le prof après coup) qui répond correctement à la question [5] :

  1. IF = (N,p) ->
  2.     [bI,bS] = [0,N]
  3.     somme = 0
  4.     until somme >= 0.025
  5.         somme += binomiale(N,p,bI++)
  6.     bI--
  7.     somme = 0
  8.     until somme >= 0.025
  9.         somme += binomiale(N,p,bS--)
  10.     bS++
  11.     [bI,bS]

Télécharger

Quelques perles du bac STI2D

Il y avait un algorithme dans le sujet métropole-Réunion de 2014, ce qui a permis de voir des situations similaires, où les élèves cherchaient avant tout à dire quels calculs on doit faire mais ignoraient souvent quoi faire avec le résultat du calcul :

  • Faire v×q
  • Faire n+1
  • Faire v×q et affecter dans v
  • Faire v×q et stocker dans v
  • ajouter n+1
  • Multiplier v par 0,9 et ajouter 1 à n

Cette dernière version, issue d’une copie assez moyenne, montre que dans au moins un cas, les opérations in situ sonnent plus naturellement que la suite « extraire→modifier→remettre dans v » suggérée par les outils classiques d’algorithmique.

Pour continuer, quelques autres perles, en dehors du sujet présent :

  • Tant que v≤120 ; Fin Tant que (sans rien entre les deux !)
  • Tant que v×qn→v
  • Tant que la valeur est 0, la valeur de q sera toujours la même

Ainsi, « augmenter x de 1 » (traduction de « incrémenter x ») ne se traduit pas automatiquement en « mettre x+1 dans x ».

Pourquoi ?

En fait, une fonction (mathématiques) associe à un nombre x un autre nombre y=f(x) ; alors qu’une transformation géométrique fait bouger un point : Elle ne l’associe pas à un autre point, mais modifie la position du même point. Le message de ces pauvres élèves martyrisés par leur prof, est qu’il leur paraît plus naturel de modifier un nombre, que de mettre le résultat d’un calcul dans une variable. En bref, ils considèrent les affectations comme des transformations sur les nombres [6]. En fait, les « programmes de calcul » du brevet des collèges suivent la même logique, comme le montre cet extrait du sujet amérique du Sud novembre 2013 :

On considère les deux programmes de calcul suivants :

Programme A

  • Choisir un nombre de départ
  • Soustraire 1 au nombre choisi
  • Calculer le carré de la différence obtenue
  • Ajouter le double du nombre de départ au résultat
  • Écrire le résultat obtenu
Programme B



  • Choisir un nombre de départ
  • Calculer le carré du nombre choisi
  • Ajouter 1 au résultat
  • Écrire le résultat obtenu

En traduisant « calculer le carré » par « élever au carré », on se retrouve avec des transformations appliquées à des nombres, qui ne sont autres que les valeurs successives de la variable x.

Idée folle : Et si on créait un langage de programmation axé sur les transformations de nombres ?

En fait, un tel langage existe depuis assez longtemps : Il s’agit de COBOL, initié par Grace Hopper. Par exemple, « ajouter 2 à x » qui, en CoffeeScript, se note x = x+2 ou x += 2, et qui a bien pour effet de transformer x, se code en COBOL :
ADD 2 TO x
D’où l’idée de chercher un COBOL en français qui tournerait en html5 (typiquement, programmé en JavaScript ou en CoffeeScript)... Or, s’il existe bien un COBOL en CoffeeScript, d’ailleurs décrit comme un langage dédié [7], celui-ci est écrit en anglais, et il subsiste le besoin de refaire tout ça en français. On va donc dans la suite de cet article, montrer comment on peut créer un tel langage spécialisé dans les transformations sur les variables, et que l’on propose d’appeler Sophus [8].


Variables transformables

La POO répond facilement à la question de la transformabilité d’une variable : Une variable est un objet, possédant une propriété appelée « valeur », qu’il est possible de modifier. Pour éviter les erreurs de syntaxe (oubli d’initialiser la variable), on donne par défaut la valeur 0 à la « valeur » de la variable :

  1. class Variable
  2.     constructor: (@valeur=0) ->
  3.     toString: -> @valeur.toString()

Télécharger

La dernière ligne a pour but de détourner l’affichage d’une variable, en affichant sa valeur à la place de [object Object] donné par CoffeeScript par défaut.

modification de la valeur

Avec cet objet simplissime, on peut déjà faire de l’algorithmique du moment qu’on définit une méthode d’affectation :

  1. class Variable
  2.     constructor: (@valeur=0) ->
  3.     toString: -> @valeur.toString()
  4.     prend: (x) -> @valeur = x

Télécharger

Après ça, on peut incrémenter x avec

  1. x = new Variable 3
  2. x.prend x*1+1
  3. alert x

Télécharger

Pas extraordinaire :

  • on doit mettre un point entre « x » et « prend »
  • il a fallu multiplier x par 1 avant d’additionner 1, sinon on aurait eu 31 au lieu de 4 : Par défaut, 3 est considéré par JavaScript comme la chaîne de caractères « 3 » et l’addition est interprétée comme une concaténation.

Ceci est un bug : Contrairement à CoffeeScript, on ne doit pas confondre le nom d’une variable (ici, x) avec sa valeur (ici, 3). On devrait donc écrire plutôt

  1. x = new Variable 3
  2. x.prend x.valeur + 2
  3. alert x

Télécharger

En effet, pour avoir la valeur de x, on écrit x.valeur, notation standard en théorie des groupes comme en programmation objet. Finalement, pour l’affectation en Sophus, on fait mieux d’écrire une fonction, en dehors de la définition de l’objet :

  1. class Variable
  2.     constructor: (@valeur=0) ->
  3.     toString: -> @valeur.toString()
  4.  
  5. mettreDans = (variable,bidule) =>
  6.     variable.valeur = bidule
  7.     null

Télécharger

L’algorithme x←3 ; x ←x+2 devient alors

  1. x = new Variable 3
  2. mettreDans x, x.valeur+2
  3. alert x

Télécharger

Résumé de cet onglet

En Sophus,

  • il est nécessaire de distinguer le nom d’une variable (sur lequel on ne peut pas opérer) de son contenu. Si x est une variable, x+1 n’a aucun sens en Sophus, mais x.valeur + 1 en a un.
  • une variable n’est donc pas accessible si elle n’a pas été initialisée, ce qui suppose qu’elle ait au préalable été créée.
  • Pour autant, il n’est pas nécessaire de mettre la liste des variables en préambule, elles peuvent être créées au fur et à mesure des besoins.
  • la notation pour l’affectation est préfixée (mettre dans x, 3) et non infixée (x prend la valeur 3, ou x=3) ; ce qui la rapproche de la notation Ti 3→x. De façon générale, les verbes sont au début des phrases, car CoffeeScript est un langage fonctionnel et que les fonctions implémentent des verbes.
  • Les verbes sont à l’infinitif dans Sophus, comme dans les sujets de bac, où l’infinitif est un impératif caché. Le premier complément du verbe est séparé de celui-ci par un espace, mais le cas échéant, suivi d’une virgule

fonctions

affichage

Pour commencer, on enrichit un peu l’affichage (« toString() ») des variables : Le message toString(), envoyé à un objet, le transforme en chaîne de caractères (mais sans modifier l’original), et pour franciser encore un peu cette chaîne de caractères, on remplace les points décimaux par des virgules :

  1. class Variable
  2.     constructor: (@valeur=0) ->
  3.     toString: -> @valeur.toString().replace(".",",")

Télécharger

Ensuite, on a souvent besoin avec JavaScript, d’arrondir les nombres, pour éviter les affichages étranges du genre 2,100000000023 au lieu de 2,1. Pour cela, on réalise une fonction d’arrondi, qui va réellement transformer les nombres :

  1. décimales = "décimales"
  2. près = "près"
  3. à = "à"
  4.  
  5.  
  6.  
  7. arrondir = (o,a="",epsilon=1,ordre="décimales") =>
  8.     if a is ""
  9.         o.valeur = Math.round(o.valeur)
  10.     if a is "à"
  11.         if ordre is "décimales"
  12.             o.valeur = Math.round(o.valeur*Math.pow(10,epsilon))/Math.pow(10,epsilon)
  13.         if ordre is "près"
  14.             o.valeur = Math.round(o.valeur/epsilon)*epsilon

Télécharger

Cette fonction est à multiples facettes, grâce aux variables globales a, près et décimales ; ainsi, pour arrondir π à l’entier le plus proche, on fait

  1. p = new Variable π
  2. arrondir p

Télécharger

Mais pour arrondir π à trois décimales, on peut faire, soit

  1. p = new Variable π
  2. arrondir p, à, 3, décimales

Télécharger

soit

  1. p = new Variable π
  2. arrondir p, à, 0.001, près

Télécharger

De façon similaire, on peut remplacer round par floor pour tronquer au lieu d’arrondir.

On peut simplifier des fonctions en enlevant le préfixe Math de JavaScript, par exemple

  1. racine = (nombre) -> Math.sqrt(nombre)
  2. sinus = (nombre) -> Math.sin(nombre*π/180)

Télécharger

(à condition d’avoir défini la variable π = Math.PI au préalable).

Mais, s’il est intéressant de redéfinir la fonction carré par

  1. carré = (nombre) ->
  2.     nombre * nombre

Télécharger

il est encore plus intéressant de définir une transformation éleverAuCarré qui transforme une variable en son carré :

  1. éleverAuCarré = (o) =>
  2.     o.valeur *= o.valeur

Télécharger

Ensuite on peut remplacer x par son carré avec quelque chose comme ceci :

  1. c = new Variable 4
  2. éleverAuCarré c
  3. alert c

Télécharger

On a ajouté les transformations éleverAuCube et inverser ainsi que extraireLaRacineDe qui transforment une variable selon des méthodes vues au collège. Cependant, les techniques exposées dans l’onglet « pourcentages » permettent de créer une instruction élever, utilisable au choix avec l’une des syntaxes suivantes :

  1. élever x, "au carré"
  2. élever x, auCarré
  3. élever x, aLaPuissance, 2
  4. élever x, "à la puissance", 2

Télécharger

entrées/sorties

Pour afficher une variable, on demande à Sophus de la montrer :

  1. montrer = (o) =>
  2.     alert o

Télécharger

Et pour entrer une variable [9], on fait ainsi :

  1. entrer = (o) =>
  2.     o.valeur = prompt "Quelle valeur donner à cette variable ?"

Télécharger

Cette fonction permet d’entrer une variable mais comme, in fine, l’exécution est faite dans le navigateur internet sous JavaScript, la variable entrée est par défaut une chaîne de caractères. Pour les cas où l’entrée de données concerne un nombre, il faudra faire

  • Pour un entier,
  1. entrer n
  2. n = parseInt n.valeur

Télécharger

  • Pour un réel,
  1. entrer x
  2. x = parseFloat n.valeur

Télécharger

Dorénavant on remplacera donc les « alert » par des « montrer ».

fonctions linéaires

Les transformations les plus fréquentes sont, outre les translations (ajouter une constante à la variable), les fonctions linéaires, dont voici la collection de Sophus :

  1. doubler = (o) =>
  2.     o.valeur *= 2
  3. tripler = (o) =>
  4.     o.valeur *= 3
  5. quadrupler = (o) =>
  6.     o.valeur *= 4
  7. quintupler = (o) =>
  8.     o.valeur *= 5
  9. sextupler = (o) =>
  10.     o.valeur *= 6
  11. octupler = (o) =>
  12.     o.valeur *= 8
  13. décupler = (o) =>
  14.     o.valeur *= 10
  15. centupler = (o) =>
  16.     o.valeur *= 100

Télécharger

La suite de Collatz notamment fait usage de « tripler ».

Pour avoir d’autres transformations linéaires, on crée une multiplication générale (par un nombre ou par une variable) :

  1. multiplier = (o,par="par",facteur) =>
  2.     if par is "par"
  3.         o.valeur *= facteur.valeur ? facteur

Télécharger

Ainsi, les deux scripts suivants ont le même effet :

  1. unNombrePair = new Variable 6
  2. doubler unNombrePair
  3. montrer unNombrePair

Télécharger

et

  1. unNombrePair = new Variable 6
  2. multiplier unNombrePair, par, 2
  3. montrer unNombrePair

Télécharger

On peut bien entendu aussi diviser par un nombre avec une syntaxe similaire à celle de la multiplication. Pour Collatz, la division par 2 est utile lorsque le nombre est pair. On peut aussi vérifier que les deux scripts suivants ont toujours le même effet :

  1. x= 3
  2. éleverAuCarré x

Télécharger

et

  1. x = 3
  2. multiplier x, par, x

Télécharger

Résumé de cet onglet

En TP d’algorithmique, il arrive souvent que des élèves se bornent à écrire une expression sans affectation. Par exemple, pour incrémenter une variable, quelque chose comme x+1. En général, une fois qu’on leur a dit « oui, c’est bien l’expression à calculer, mais ensuite on en fait quoi du résultat de ce calcul ? », ils se sentent perdus, et les plus hardis d’entre eux osent un « bonne question, j’aimerais bien le savoir » qui ne les fait guère avancer. Alors

  • Algobox propose comme remédiation de ne pas permettre d’écrire une expression autrement que après un « prend la valeur » ou un « afficher ». Les mêmes élèves ont d’ailleurs du mal à rédiger leur algorithme avec Algobox ;
  • Avec Sophus, la question de « où stocker l’expression après l’avoir calculée ? » ne se pose plus systématiquement, puisque la réponse est souvent « sur place ».

incrémentation

L’incrémentation est une opération très importante sur les nombres entiers puisqu’elle sert à compter. Les « range » de Python (langage) sont d’ailleurs une version active de l’incrémentation. En fait, l’incrémentation est une version opératoire du deuxième des axiomes de Peano.

Pour incrémenter un nombre, on peut lui ajouter 1 avec l’instruction « ajouter » décrite dans le prochain onglet, mais plus simplement, utiliser le verbe « incrémenter » [10] avec la fonction suivante :

  1. incrémenter = (o) =>
  2.     o.valeur += 1
  3.     null

Télécharger

Cette fonction renvoit « null » pour éviter les effets de bords dans CoffeeScript.

Programme B

Avec cette incrémentation, le programme B du sujet de brevet des collèges amérique du Sud novembre 2013 peut être transformé en fonction B(x) avec

  1. B = (unNombreDeDépart) ->
  2.     x = new Variable unNombreDeDépart
  3.     éleverAuCarré x
  4.     incrémenter x
  5.     x

Télécharger

Voici la représentation graphique de cette fonction réalisée avec l’outil alcoffeethmique téléchargeable ci-dessus :

-8-7-6-5-4-3-2-101234567891011120102030405060708090100110120130140150160


De même, on peut décrémenter une variable de la manière suivante :

  1. décrémenter = (o) =>
  2.     o.valeur -= 1
  3.     null

Télécharger

Programme A

La décrémentation permet de programmer la fonction A du sujet brevet des collèges amérique du Sud novembre 2013, ainsi (avec l’instruction « augmenter » décrite dans l’onglet suivant) :

  1. A = (unNombreDeDépart) ->
  2.     x = new Variable unNombreDeDépart
  3.     y = new Variable unNombreDeDépart
  4.     décrémenter x
  5.     éleverAuCarré x
  6.     doubler y
  7.     augmenter x, de, y
  8.     x.valeur

Télécharger

Voici la représentation graphique de la fonction A(x) dans le même repère que la fonction B ci-dessus, en rouge ; on voit que seule la couleur est différente ce qui montre l’égalité entre les deux fonctions :

-8-7-6-5-4-3-2-101234567891011120102030405060708090100110120130140150160

L’incrémentation sert à parcourir une suite arithmétique de raison 1, typiquement celles des entiers naturels. Une première généralisation, où la raison n’est pas nécessairement 1, est développée dans l’onglet suivant.

pourcentages

On peut ensuite penser à quelque chose comme

  1. augmenter =(o,increment) =>
  2.     o.valeur += increment

Télécharger

Mais dans ce cas, la syntaxe s’éloigne de la langue française [11] puisque pour incrémenter un indice on ferait

  1. indice = new Variable
  2. augmenter indice, 1

Télécharger

Pour retrouver le dynamisme de la langue de Molière [12], il suffit d’ajouter une variable qui devra nécessairement être égale au texte « de » (et on peut se passer de guillemets en créant une variable globale de même nom. Alors

  1. de = "de"
  2. augmenter =(o,de="de",increment) =>
  3.     if de is "de"
  4.         o.valeur += increment
  5.     else
  6.         montrer "De combien voulez-vous donc que j'augmente cette variable à la fin ?"

Télécharger

permet d’incrémenter l’indice en écrivant

  1. indice = new Variable
  2. augmenter indice, de, 1

Télécharger

suffixes

On peut continuer en ajoutant quelque chose après l’incrément ! Pareil, on met un mot (représentant un dénominateur comme « pourcents » [13]) et selon le mot choisi, l’opération à effectuer est rappelée. Dans le cas des pourcentages, la formule est utilisée au quotidien en STMG, sans que tous les élèves, loin s’en faut, la maîtrisent...

Le script est plus long, de par l’abondance des mots choisis. C’est une très bonne occasion pour effectuer des tests multiples avec switch...when :

  1. de = "de"
  2. pourcents = "pourcents"
  3. [demis,tiers,quarts,cinquièmes,sixièmes,septièmes,huitièmes,neuvièmes,dixièmes] = ["demis","tiers","quarts","cinquièmes","sixièmes","septièmes","huitièmes","neuvièmes","dixièmes"]
  4.  
  5.  
  6.  
  7. augmenter = (o,de,chouia,mode="") =>
  8.     if de is "de"
  9.         switch mode
  10.             when ""
  11.                 o.valeur += chouia.valeur ? chouia
  12.             when "demis"
  13.                 o.valeur *= (1+(chouia.valeur ? chouia)/2)
  14.             when "tiers"
  15.                 o.valeur *= (1+(chouia.valeur ? chouia)/3)
  16.             when "quarts"
  17.                 o.valeur *= (1+(chouia.valeur ? chouia)/4)
  18.             when "cinquièmes"
  19.                 o.valeur *= (1+(chouia.valeur ? chouia)/5)
  20.             when "sixièmes"
  21.                 o.valeur *= (1+(chouia.valeur ? chouia)/6)
  22.             when "septièmes"
  23.                 o.valeur *= (1+(chouia.valeur ? chouia)/7)
  24.             when "huitièmes"
  25.                 o.valeur *= (1+(chouia.valeur ? chouia)/8)
  26.             when "neuvièmes"
  27.                 o.valeur *= (1+(chouia.valeur ? chouia)/9)
  28.             when "dixièmes"
  29.                 o.valeur *= (1+(chouia.valeur ? chouia)/10)
  30.             when "pourcents"
  31.                 o.valeur *= (1+(chouia.valeur ? chouia)/100)
  32.     else
  33.         alert "Je veux bien augmenter cette variable mais de combien ?"
  34.     null

Télécharger

On remarque au passage d’autres enrichissements de la fonction « augmente » :

  • Les points d’interrogation sont des tests d’existence en CoffeeScript ; ils permettent d’augmenter la variable o, soit par un nombre, soit par une autre variable ;
  • Si on crée une variable dont la valeur est textuelle, on peut utiliser l’augmentation pour y concaténer une autre variable textuelle puisque l’addition dénote la concaténation quand on parle de chaînes de caractères. Par exemple texte = new Variable "bon"; augmenter texte, de, "jour"
  • CoffeeScript autorise à ne pas entrer la dernière variable (le suffixe) à condition qu’elle soit prédéfinie. Une seule définition de fonction gère donc tous les cas.
  • Si la troisième variable n’est pas égale à « de », c’est qu’il y a une erreur de syntaxe, et celle-ci empêche une tentative d’augmentation de la variable, tout en affichant un message d’erreur.

Avec ceci, on peut écrire des algorithmes à la STMG :

  1. année = new Variable 2014
  2. capital = new Variable 800
  3. #copier-coller plusieurs fois ce qui est ci-dessous si on a peur des boucles :
  4. incrémenter année
  5. augmenter capital, de, 2.3, pourcents
  6. arrondir capital, à, 2, décimales

Télécharger

On peut également diminuer une variable dans les mêmes conditions.

tests et boucles

La difficulté à faire évaluer en temps réel les booléens fait que les tests multiples (« else », « switch ») ne peuvent pas facilement être programmés fonctionnellement, ni les boucles « while » et « until ». Sophus ne connaît donc que les boucles simples (sans indice) et les tests simples (sans clause alternative).

Théorie

En lambda-calcul, pour programmer une boucle

Pour Sophus, on a donc préféré la programmation objet, en représentant

  • les boucles « répète » de Logo (langage), comme méthodes de l’objet nombre (en fait, les entiers) de JavaScript ;
  • les recherches de seuil comme méthodes de l’objet nombre (réels) de JavaScript.

Tests

Dans l’esprit de Sophus, qui transparaît dans les onglets précédents, la fonction suivante permet de faire un test simple :

  1. si = (booleen,fonction) ->
  2.     do fonction if booleen
  3.     null

Télécharger

Le « sinon » n’étant pas permis, on peut le compenser par un second test, dont le booléen est le contraire du premier. Par exemple pour la suite de Collatz, une fois qu’on a regardé si un est pair, on regarde s’il est impair :

  1. collatz = new Variable 3
  2. U=[collatz]
  3. 8.foisFaire ->
  4.     si collatz.estImpair(), ->
  5.         tripler collatz
  6.         incrémenter collatz
  7.         null
  8.     si collatz.estPair(), ->
  9.         diviser collatz, par, 2
  10.         null
  11.     U.empiler collatz.valeur
  12. montrer U

Télécharger

La fonction suivante fonctionne [14] aussi :

  1. aMoinsQue = (booleen,fonction) ->
  2.     do fonction unless booleen
  3.     null

Télécharger


Boucles

Le langage LOGO, destiné à des enfants, possédait une boucle « repeat » permettant simplement de faire quelque chose plusieurs fois, en modifiant éventuellement quelques variables dans la boucle. Aussi lorsque Alan Kay a créé le langage Smalltalk, a-t-il conservé [15] cette boucle sans indice, comme méthode de l’objet « entier ». Dans Sophus cette boucle existe aussi, elle s’appelle foisFaire et on l’a vue ci-dessus dans l’exemple de la suite de Collatz.

Si par malheur on a besoin d’utiliser l’indice de la boucle (par exemple pour additionner les valeurs successives de celui-ci) on peut toujours en créer un avant la boucle, et l’incrémenter dans la boucle. Attention toutefois à ne pas modifier l’indice dans la boucle, c’est un risque avec la modification in situ. Par exemple, pour additionner les 10 premiers nombres entiers en Sophus, on peut faire ainsi, avec deux variables somPart stockant la somme partielle au cours de la boucle, et indice matérialisant l’indice de la boucle :

  1. #pour calculer 0+1+2+...+9
  2. somPart = new Variable 0
  3. indice  = new Variable 0
  4. 10.foisFaire ->
  5.     augmenter somPart, de, indice
  6.     incrémenter indice
  7.  
  8. montrer somPart

Télécharger

Il est possible de modifier ce « SophuScript » en ajoutant un affichage dans la boucle :

  1. #pour calculer 0+1+2+...+9
  2. somPart = new Variable 0
  3. indice  = new Variable 0
  4. 10.foisFaire ->
  5.     augmenter somPart, de, indice
  6.     incrémenter indice
  7.     montrer "#{indice} : #{somPart}"
  8.  
  9. montrer somPart

Télécharger

Le secret des boucles en Sophus

La programmation des boucles se fait ainsi :

  1. Number::foisFaire = (fn) -> do fn for i in [0...this]
  2. Number::tantQuePlusGrandQue = (variable,fn) -> do fn while variable<this
  3. Number::tantQuePlusPetitQue = (variable,fn) -> do fn while variable>this

Télécharger

Genèse des boucles en Sophus

Voici un extrait d’un « hangout » (version Google du « chat ») entre les deux auteurs (dont l’un était grippé) relatant la découverte de boucles qui fonctionnent, et du coup, de booléens qui s’affichent en Français :

genèse des booléens :
« hangout » Gmail relatant la genèse des booléens en Français

Pour les boucles à condition de sortie, on peut comparer avec un seuil, par exemple voici le corrigé sophusien du bac ES Antilles-Guyane septembre 2013. La condition « le nombre d’adhérents est inférieur à 180 » se traduit en Sophus par "180 est plus grand que le nombre d’adhérents :

  1. année = new Variable 2005
  2. adhérents = new Variable 80
  3. 180.tantQuePlusGrandQue adhérents, ->
  4.         incrémenter année
  5.         diminuer adhérents, de, 10, pourcents
  6.         augmenter adhérents, de, 20
  7.         arrondir adhérents
  8.  
  9. montrer année

Télécharger

Un autre exemple : Combien de fois doit-on lancer un dé pour que la probabilité d’avoir au moins une fois un 6 dépasse 99 chances sur 100 ?

La probabilité de ne pas avoir de 6 est une suite géométrique de raison 5/6, on passe donc de chaque terme au suivant en enlevant un sixième de celui-ci. On veut que la probabilité du contraire passe en-dessous de 0,01 :

  1. probabilité = new Variable 1 #au début la probabilité de ne pas avoir de 6 est 1
  2. tentatives = new Variable 0 # puisqu'on n'a pas encore lancé le dé
  3. 0.01.tantQuePlusPetitQue probabilité, ->
  4.     diminuer probabilité, de, 1, sixième
  5.     incrémenter tentatives
  6.  
  7. montrer tentatives

Télécharger


Il est toujours possible de programmer en Sophus avec des boucles classiques et des tests multiples, puisque ceux-ci sont disponibles en CoffeeScript, qui est le support de Sophus. La situation est d’ailleurs tout-à-fait analogue pour la Ti82Stats-fr, à en juger par les copies d’écran suivantes :


Comme sophus (interpréteur de Sophus) est libre, il est normal que son téléchargement soit aisé. Le voici donc en version source et en version JavaScript (à mettre dans un fichier html) :

le source le JavaScript l’interpréteur hors ligne
source en CoffeeScript
langage de programmation Sophus
sophus en JavaScript
utilitaire de programmation Sophus
sophus
Utilitaire de programmation en langage Sophus

Liste des instructions

ActionExemple
créer une variablev = new Variable 22/7
affecter la variable vmettreDans v, "un texte"
entrer une variable ventrer v
Afficher une variable vmontrer v
arrondir une variable v à l'entier le plus prochearrondir v
arrondir une variable v à 0,05 prèsarrondir v, à, 0.05, près
arrondir une variable v au centièmearrondir v, à, 2, décimales
tronquer une variable vcomme les arrondis mais avec "tronquer" au lieu de "arrondir"
ajouter 1 à une variable vincrémenter v
ajouter 2 à une variable vaugmenter v, de, 2
augmenter une variable v de deux cinquièmesaugmenter v, de, 2, cinquièmes
augmenter une variable v de trois pourcentsaugmenter v, de, 3, pourcents
soustraire 1 à une variable vdécrémenter v
soustraire un nombre, une fraction ou un pourcentage à une variable vcomme pour ajouter mais "diminuer" au lieu de "augmenter"
multiplier une variable v par un entier entre 2 et 6tripler v
multiplier une variable v par 8octupler v
multiplier une variable v par 10décupler v
multiplier une variable v par 100centupler v
multiplier une variable v par 1000multiplier v, par, 1000
diviser une variable v par un nombre non nuldiviser v, par, 3
remplacer une variable v par son carrééleverAuCarré v
variante pour remplacer une variable v par son carréélever v, "au carré"
remplacer une variable v par son cubeéleverAuCube v
remplacer une variable v par sa puissance quatrièmeélever v, "à la puissance", 4
remplacer une variable v par son inverseinverser v
remplacer une variable v par sa racine carréeextraireLaRacineDe v

Et voici un interpréteur Sophus en ligne :

Interpréteur Sophus

© IREM de La Réunion: Alain Busser, Florian Tobé 2014

Exemples

On peut tester l’interpréteur Sophus ci-dessus avec les scripts ci-dessous, concernant des sujets d’examen de la session 2014.

Bac ES Amérique du Nord

Afin d’entretenir une forêt vieillissante, un organisme régional d’entretien des forêts décide d’abattre chaque année 5% des arbres existants et de replanter 3 000 arbres.
Le nombre d’arbres de cette forêt est modélisé par une suite notée u où un désigne le nombre d’arbres au cours de l’année (2013+n).
En 2013, la forêt compte 50 000 arbres.

Voici l’algorithme de la fin de la question (recherche d’un seuil ; plus précisément quand le nombre d’arbres dépassera 57000) :

  1. arbres = new Variable 50000
  2. année = new Variable 2013
  3. 57000.tantQuePlusGrandQue arbres, ->
  4.     diminuer arbres, de, 5, pourcents
  5.     augmenter arbres, de, 3000
  6.     incrémenter année
  7. montrer année

Télécharger

DNB

Voici un programme de calcul :

Choisirunnombre Multiplierlesdeuxnombresobtenus Résultat soustraire6 soustraire2 1

1. Montrer que si on choisit 8 comme nombre de départ, le programme donne 12 comme résultat.
2. Pour chacune des affirmations suivantes, indiquer si elle est vraie ou fausse. On rappelle que les réponses doivent être justifiées.
Proposition 1 Le programme peut donner un résultat négatif ;
Proposition 2 si on choisit 1/2 comme nombre de départ, le programme donne
33/4 comme résultat ;
Proposition 3 Le programme donne 0 comme résultat pour exactement deux nombres ;
Proposition 4 la fonction qui, au nombre de départ, associe le résultat du programme est une fonction linéaire.

Question 1

Pour répondre à la question 1, on transforme le programme de calcul en suite d’instructions Sophus. Mais les variables locales gauche et droite doivent être créées et initialisées avec la valeur de la variable nombre (soit, avec 8).

  1. nombre = new Variable 8
  2. gauche = new Variable nombre
  3. droite = new Variable nombre
  4. diminuer gauche, de, 6
  5. diminuer droite, de, 2
  6. multiplier gauche, par, droite
  7. montrer gauche

Télécharger


Question 2

Pour répondre à la question 2, il est plus pratique de transformer le programme de calcul en une fonction.

Pour la proposition 2, on à juste à afficher l’image de 1/2 par la fonction :

  1. Programme = (nombre) ->
  2.     gauche = new Variable nombre
  3.     droite = new Variable nombre
  4.     diminuer gauche, de, 6
  5.     diminuer droite, de, 2
  6.     multiplier gauche, par, droite
  7.     gauche
  8.  
  9. montrer Programme 1/2

Télécharger

Pour les autres propositions, on peut constituer un tableau de valeurs en empilant les images d’entiers successifs par cette fonction, dans un tableau :

  1. Programme = (nombre) ->
  2.     gauche = new Variable nombre
  3.     droite = new Variable nombre
  4.     diminuer gauche, de, 6
  5.     diminuer droite, de, 2
  6.     multiplier gauche, par, droite
  7.     gauche
  8.  
  9. variable = new Variable 0
  10. tabval = []
  11. 8.foisFaire ->
  12.     tabval.empiler Programme(variable)
  13.     incrémenter variable
  14.  
  15. montrer tabval

Télécharger

Bac ES Pondichery

Une association décide d’ouvrir un centre de soin pour les oiseaux sauvages victimes de la pollution. Leur but est de soigner puis relâcher ces oiseaux une fois guéris.
Le centre ouvre ses portes le 1er janvier 2013 avec 115 oiseaux.
Les spécialistes prévoient que 40% des oiseaux présents dans le centre au 1er janvier d’une année restent présents le 1er janvier suivant et que 120 oiseaux nouveaux sont accueillis dans le centre chaque année.
On s’intéresse au nombre d’oiseaux présents dans le centre au 1er janvier des années suivantes.

Voici l’algorithme en Sophus :

  1. oiseaux = new Variable 115
  2. année = new Variable 2013
  3. durée = parseInt(prompt "pendant combien d'années ?")
  4. durée.foisFaire ->
  5.     diminuer oiseaux, de, 60, pourcents
  6.     augmenter oiseaux, de, 120
  7.     incrémenter année
  8. montrer année

Télécharger

La seule difficulté est que la durée est un entier à entrer, ce qui oblige à convertir la valeur entrée (par défaut, du texte) en entier.

Bac ES Liban

La médiathèque d’une petite ville a ouvert ses portes le 2 janvier 2013 et a enregistré 2 500 inscriptions en 2013.
Elle estime que, chaque année, 80% des anciens inscrits renouvelleront leur inscription l’année suivante et qu’il y aura 400 nouveaux adhérents.
On modélise cette situation par une suite numérique (an).
On note a0 = 2500 le nombre d’inscrits à la médiathèque en 2013 et an représente le nombre d’inscrits à la médiathèque
pendant l’année 2013+n.

Voici la traduction de l’algorithme de l’énoncé (recherche de seuil : Quand le nombre d’adhérents passe en-dessous de 2050) :

  1. adhérents = new Variable 2500
  2. année = new Variable 2013
  3. 2050.tantQuePlusPetitQue adhérents, ->
  4.     diminuer adhérents, de, 20, pourcents
  5.     augmenter adhérents, de, 400
  6.     incrémenter année
  7. montrer année

Télécharger

Bac ES Centres étrangers

Dans une ville, un nouveau lycée vient d’ouvrir ses portes et accueille pour sa première rentrée 500 élèves. D’une année sur l’autre, le proviseur du lycée prévoit une perte de 30% de l’effectif et l’arrivée de 300 nouveaux élèves.
On modélise cette situation par une suite numérique...

La difficulté est qu’une fois de plus, on demande d’entrer une donnée (alors qu’il aurait été tellement plus simple de l’initialiser...). Il faut alors la convertir en un entier puisque par défaut, JavaScript convertit automatiquement tout en chaînes de caractères :

  1. élèves = new Variable 500
  2. année = new Variable 2013
  3. durée = parseInt(prompt "pendant combien d'années ?")
  4. durée.foisFaire ->
  5.     diminuer élèves, de, 30, pourcents
  6.     arrondir élèves
  7.     augmenter élèves, de, 300
  8.     incrémenter année
  9. montrer élèves

Télécharger

Bac ES Polynésie

Le sujet portait sur une suite récurrente $(u_n)$ définie par

  • $u_0=5$
  • $u_{n+1}=\frac{1}{2}u_n +1$

L’algorithme étant un simple algorithme d’affichage des termes de la suite.

Première version : Afficher, en boucle, tous les termes :

  1. u = new Variable 5
  2. N = 4
  3.  
  4. N.foisFaire ->
  5.     diviser u, par, 2
  6.     incrémenter u
  7.     montrer u

Télécharger

Deuxième version : Avec un seul affichage, celui d’un tableau dans lequel on empile successivement les termes de la suite :

  1. u = new Variable 5
  2. suite = []
  3. N = 4
  4.  
  5. N.foisFaire ->
  6.     suite.empiler u
  7.     diviser u, par, 2
  8.     incrémenter u
  9. montrer suite

Télécharger

Bac ES Antilles-Guyane

Obligatoire

Un opérateur de téléphonie mobile constate que, chaque année, il perd 8% de ses précédent abonnés et que, par ailleurs, il gagne 3millions de nouveaux abonnés.
En 2013 le nombre d’abonnés est de 20 millions.
On s’intéresse au nombre d’abonnés, en millions, pour l’année 2013+n.
[...]
Compte tenu des investissements, l’opérateur considère qu’il réalisera des bénéfices lorsque le nombre d’abonnés dépassera 25 millions.

On modélise le nombre d’abonnés, en millions, par la suite $(u_n)$ telle que

  • $u_0=20$
  • $u_{n+1}=0,92 u_n + 3$

Mais voici une description plus sophusienne de la suite :

  1. abonnés = new Variable 20000000
  2. année = new Variable 2013
  3. 25000000.tantQuePlusGrandQue abonnés, ->
  4.     diminuer abonnés, de, 8, pourcents
  5.     augmenter abonnés, de, 3000000
  6.     arrondir abonnés, à, 1000, près   #choix de l'énoncé...
  7.     incrémenter année
  8. montrer année

Télécharger

L’algorithme, donné dans l’énoncé, visait à déterminer quand l’opérateur réalisera des bénéfices.


Spécialité

Les services commerciaux d’une grande surface de produits alimentaires ont défini un profil de client qui a été appelé « consommateur bio ».
Sur la base d’observations réalisées les années précédentes, il a été constaté que :
90% des clients « consommateur bio »maintenaient cette pratique l’année suivante ;
15% des clients n’ayant pas le profil de « consommateur bio » entraient dans la catégorie « consommateur bio » l’année suivante.
On suppose que cette évolution se poursuit d’une année à l’autre à partir de 2013, année au cours de laquelle il a été constaté que 20% des clients ont le profil « consommateur bio ».

Le calcul matriciel dans Sophus ressemble donc à ceci :

  1. N = new Variable 0
  2. B = new Variable 0.2
  3. C = new Variable 0.8
  4. 0.5.tantQuePlusGrandQue B, ->
  5.     diminuer B, de, 10, pourcents
  6.     multiplier C, par, 0.15
  7.     augmenter B, de, C
  8.     mettreDans C, 1-B.valeur
  9.     incrémenter N
  10. montrer N

Télécharger

Bac ES Asie

Pour modéliser l’évolution temporelle de la population d’une ville, on résout approximativement une équation en échantillonnant une fonction pour la transformer en suite, et en cherchant un seuil pour cette suite :

  1. f = (x) ->
  2.     y = new Variable Math.exp(-0.05*x)
  3.     doubler y
  4.     incrémenter y
  5.     inverser y
  6.     tripler y
  7.     y
  8.  
  9. X = new Variable 0
  10. 2.tantQuePlusGrandQue f(X), ->
  11.     incrémenter X
  12.  
  13. montrer X

Télécharger

Ce script permet de montrer comment on peut programmer une fonction en Sophus.

Bac ES métropole-Réunion

Obligatoire

À l’automne 2010, Claude achète une maison à la campagne ; il dispose d’un terrain de 1 500 m² entièrement engazonné.
Mais tous les ans, 20% de la surface engazonnée est détruite et remplacée par de la mousse. Claude arrache alors, à chaque automne, la mousse sur une surface de 50 m² et la remplace par du gazon.

On veut savoir quand Claude aura moins de 500 m² de gazon épargné par la mousse.

Voici la solution en Sophus :

  1. surface = new Variable 1500
  2. année = new Variable 2010
  3.  
  4. 500.tantQuePlusPetitQue surface, ->
  5.     incrémenter année
  6.     diminuer surface, de, 20, pourcents
  7.     augmenter surface, de, 50
  8.  
  9. montrer année

Télécharger


Spécialité

Alice participe à une compétition de tir à l’arc ; elle effectue plusieurs lancers de flèches.
Lorsqu’elle atteint la cible à un lancer, la probabilité qu’elle atteigne la cible au lancer suivant est égale à 0,9.
Lorsqu’elle a manqué la cible à un lancer, Alice se déconcentre et la probabilité qu’elle atteigne la cible au lancer suivant est égale à 0,4.
On suppose qu’au premier lancer, elle a autant de chances d’atteindre la cible que de la manquer.

Pour connaître la probabilité qu’Alice atteigne la cible au bout de 5 lancers, on calcule des puissances de matrices. Ici Sophus est plutôt classique avec ses affectations :

  1. a = new Variable 0.5
  2. b = new Variable 0.5
  3. n = 5
  4. i = new Variable 2
  5. (n-2).foisFaire ->
  6.     mettreDans a, 0.9*a.valeur+0.4*b.valeur
  7.     mettreDans b, 1-a.valeur
  8.  
  9. montrer a
  10. montrer b

Télécharger

Bac S Amérique du Nord

Voici le sujet :

Un volume constant de 2 200 m3 d’eau est réparti entre deux bassins A et B.
Le bassin A refroidit une machine. Pour des raisons d’équilibre thermique on crée
un courant d’eau entre les deux bassins à l’aide de pompes.
On modélise les échanges entre les deux bassins de la façon suivante :
• au départ, le bassin A contient 800m3 d’eau et le bassin B contient 1 400m3
d’eau ;
• tous les jours, 15% du volume d’eau présent dans le bassin B au début de
la journée est transféré vers le bassin A ;
• tous les jours, 10% du volume d’eau présent dans le bassin A au début de
la journée est transféré vers le bassin B.

La quantité d’eau dans le bassin A est alors modélisée (voir la suite du sujet) par une suite récurrente $a$ telle que $a_0=800$ et $a_{n+1}=\frac{3}{4} a_n + 330$. On cherche à partir de quand $a_n \geq 1100$ :

Le script Sophus suivant permet de répondre sans utiliser le vocabulaire spécifique des suites récurrentes :

  1. jour = new Variable 0 # le numéro du jour
  2. bassinA = new Variable 800 # au jour 0 le bassin A contient 800 mètres cubes
  3. 1100.tantQuePlusGrandQue bassinA, ->
  4.     diminuer bassinA, de, 1, quart
  5.     augmenter bassinA, de, 330
  6.     incrémenter jour
  7. montrer jour

Télécharger

Bac S Polynésie

Sujet « spécialité »

Un magicien essaye de deviner le jour de l’anniversaire d’une personne dans la salle, à partir du résultat d’un programme de calcul :

Lors d’une autre représentation, le magicien décide de changer son programme de
calcul. Pour un spectateur dont le numéro du jour de naissance est j et le numéro
du mois de naissance est m, le magicien demande de calculer le nombre z défini par
z = 12j +31m.
Dans les questions suivantes, on étudie différentes méthodes permettant de retrouver
la date d’anniversaire du spectateur.

Le script en CoffeeScript ressemble à l’algorithme du sujet :

  1. nom = ['janvier','février','mars','avril','mai','juin','juillet','août','septembre','octobre','novembre','décembre']
  2. for mois in [1..12]
  3.     for jour in [1..31]
  4.         z = 12*jour+31*mois
  5.         if z is 503
  6.             alert "La personne est née le #{jour}ième jour du mois de #{nom[mois]}"

Télécharger

Voici, à fins de comparaison, la version Sophus (les deux peuvent être testées ci-dessus) :

  1. z = new Variable #variable à tester dans la boucle
  2. mois = new Variable 1 #numéro du mois
  3. 12.foisFaire ->   # il y a 12 mois...
  4.     jour = new Variable 1 #numéro du jour dans le mois
  5.     31.foisFaire ->   # il y a 31 jours maximum dans le mois
  6.         mettreDans z, 12*jour.valeur+31*mois.valeur
  7.         si z.valeur == 503, ->
  8.             montrer jour
  9.             montrer mois
  10.         incrémenter jour
  11.     incrémenter mois

Télécharger

Bac S Antilles-Guyane

Obligatoire

Le sujet portait sur la suite récurrente $(u_n)$ définie par

  • $u_0=2$
  • $u_{n+1}=\frac{1}{5}u_n + 3 \times 0.5^n$

La version Sophus est un autre point de vue :

  1. n = new Variable 0
  2. u = new Variable 2
  3. p = new Variable 3
  4. 0.01.tantQuePlusPetitQue u, ->
  5.     incrémenter n
  6.     diviser p, par, 2
  7.     diviser u, par, 5
  8.     augmenter u, de, p
  9. montrer n

Télécharger


Spécialité

En montagne, un randonneur a effectué des réservations dans deux types d’hébergements :

L’hébergement A et l’hébergement B.
Une nuit en hébergement A coûte 24 € et une nuit en hébergement B coûte 45 €.
Il se rappelle que le coût total de sa réservation est de 438 €.
On souhaite retrouver les nombres x et y de nuitées passées respectivement en hébergement A et en hébergement B

Comme il faut boucler sur des indices, Sophus nous oblige à créer ces indices x et y, puis à les incrémenter dans la boucle :

  1. x = new Variable 0
  2. 18.foisFaire ->
  3.     y = new Variable 0
  4.     9.foisFaire ->
  5.         A = new Variable x.valeur
  6.         multiplier A, par, 24 # 24 € par nuit pour la chambre A
  7.         B = new Variable y.valeur
  8.         multiplier B, par, 45 # 45 € par nuit, pour y nuits
  9.         prixTotal = A
  10.         augmenter prixTotal, de, B
  11.         si prixTotal.valeur == 438, ->
  12.             montrer x
  13.             montrer y
  14.         incrémenter y
  15.     incrémenter x

Télécharger

Bac S Asie

Pour calculer des intégrales par la méthode des rectangles, Sophus est tout indiqué avec son instruction ajouter :

  1. n = new Variable 0
  2. entrer n
  3.  
  4. f = (x) ->
  5.     y = new Variable x.valeur
  6.     élever y, "à la puissance", n.valeur
  7.     incrémenter y
  8.     inverser y
  9.     y
  10.  
  11. I = new Variable 0
  12. x = new Variable 0
  13. p = new Variable
  14. entrer p
  15. p = parseInt(p.valeur) # convertir la variable p en un entier
  16. p.foisFaire ->
  17.     pas = f(x)
  18.     diviser pas, par, p
  19.     augmenter I, de, pas
  20.     augmenter x, de, 1/p
  21.  
  22. montrer I

Télécharger

Quelques remarques sur les types des variables :

  • n est une variable de type Variable puisqu’elle a été initialisée comme tel.
  • On doit donc faire appel à n.valeur pour la traiter comme un entier.
  • La fonction f admet en entrée, un réel (transformé en variable y au début de sa description) ; elle retourne une variable Sophus.
  • Lors de sa création, le nombre de termes p est une Variable, dont la valeur est entrée au clavier.
  • Mais p.valeur est une chaîne de caractère (facétie de JavaScript) et la ligne commençant par parseInt transforme p en un entier. p n’est alors plus une variable Sophus mais un entier JavaScript