La moyenne du terrassier
publication: 20 mai 2024 / mis à jour 20 mai 2024
article: 11 avril 2020 / mis à jour 18 avril 2020
Calcul de la moyenne
Nous avons tous appris à calculer une moyenne. Il suffit de faire la somme de N nombres et de diviser cette somme par N. Exemple:
- Mickael a trois notes en contrôle mensuel de math: 10 10 et 20
- on fait la somme de ces trois valeurs et on obtient 40
- on divise cette somme par 3, ce qui nous donne la moyenne de 13.33...
Beaucoup d'autres combinaisons permettent d'aboutir à cette moyenne:
- Charles:
(16+10+14)/3
- Henri:
(18+17+5)/3
Commencez-vous à saisir le problème?
En calculant une moyenne brute, nous n'arrivons pas à savoir si les élèves s'améliorent, stagnent ou sont en baisse. Pour Mickael, il est évident que ses notes accusent une amélioration impressionnante, alors que Charles a eu une faiblesse en cours de trimestre. Pour Henri, c'est la chute libre.
La moyenne du terrassier
Nous allons voir un moyen astucieux pour calculer la moyenne d'une autre manière, un moyen qui va permettre en particulier de déterminer si une situation évolue ou stagne.
Prenons le cas d'un terrassier qui doit combler un terrain pour le rendre plat en vue de construire une terrasse:
Ici, le terrain, à partir du point A est plat jusqu'au point B, puis est en pente du point B au point C.
Le terrassier doit remplir avec du béton et des granulats la partie de terrain colorée en vert. La hauteur de matériaux à amener est de 10 cm aux points A et B, puis de 20 cm au point C.
Si on fait la moyenne des hauteurs en A, B et C, on aura comme résultat
(10+10+20)/3=13.33..
Quelques mois plus tard, notre même terrassier a un chantier similaire, mais doit combler ce terrain:
Faisons la moyenne des hauteurs A, B et C: (10+20+10)/3=13.33..
Pourtant, il n'y a pas du tout - mais alors vraiment pas du tout - le même volume de matière à couler.
Pour calculer le volume de matière à amener, on peut faire un calcul de géométrie. Pour notre part, nous allons aborder le problème d'une autre manière.
Les moyennes de moyennes
Le point médian situé entre A et B a une hauteur qui sera la valeur moyenne des hauteurs mesurées en A et B. C'est pareil pour le point médian situé entre B et C. Retrouvons le calcul de ces hauteurs moyennes ici:
A | B | C | ||
---|---|---|---|---|
10 | 10 | 20 | ||
10 | 15 |
Nous obtenons deux moyennes qui semblent correspondre aux hauteurs de terrain à combler:
(A+B)/2=10
hauteur située entre A et B --> M1(B+C)/2=15
hauteur située entre B et C --> M2
La moyenne de ces moyennes M1 et M2 sera (M1+M2)/2=12.5
Refaisons le calcul de ces moyennes, appliqué au second cas de terrassement:
A | B | C | ||
---|---|---|---|---|
10 | 20 | 10 | ||
15 | 15 |
Calcul des deux moyennes:
(A+B)/2=15
hauteur située entre A et B --> M1(B+C)/2=15
hauteur située entre B et C --> M2
La moyenne de ces moyennes M1 et M2 sera (M1+M2)/2=15
Rien qu'en modifiant l'ordre des données initiales, nous n'obtenons pas la même moyenne de moyenne! Les résultats semblent correspondre à la hauteur moyenne de matière à amener pour aménager les terrains de notre terrassier...
Application générale
Appliquons ce calcul de moyennes de moyennes aux notes de nos élèves:
Mickael:
A | B | C | ||
---|---|---|---|---|
10 | 10 | 20 | ||
10 | 15 | |||
12.5 |
Charles:
A | B | C | ||
---|---|---|---|---|
16 | 10 | 14 | ||
13 | 12 | |||
12.5 |
Henri:
A | B | C | ||
---|---|---|---|---|
18 | 17 | 5 | ||
17.5 | 11 | |||
14.25 |
Pour des raisons de facilités, abrégons par Mt cette moyenne de moyennes.
Analysons ces résultats:
- les moyennes Mt de Mickael et Charles sont identiques: 12.5;
- la moyenne Mt de Mickael est calculée à partir des valeurs 10 et 15. La seconde valeur est supérieur à la première, on en déduit que les résulats de Mickael sont en progression;
- la moyenne Mt de Charles est calculée à partir des valeurs 13 et 12. La seconde valeur est inférieure à la première, on en déduit que les résulats de Charles sont en régression;
- la moyenne Mt de Henri est calculée à partir des valeurs 17.5 et 11. La seconde valeur est inférieure à la première. Les résulats de Henri sont en régression. Cette régression est beaucoup plus importante que celle de Charles.
Formalisation
Pour calculer une moyenne Mt de 3 valeurs A, B et C, voici la formule générale:
Mt = ( ( ( A + B ) / 2 ) + ( ( B + C ) / 2 ) ) / 2 = ( ( A + B + B + C ) / 2 ) / 2 = ( A + 2B + C ) / 4
Nous avons donc un divisieur, ici 4.
Il n'est donc pas nécessaire de faire les moyennes intermédiaires. Il suffit de faire les sommes intermédiaires:
Henri:
A | B | C | ||
---|---|---|---|---|
18 | 17 | 5 | ||
35 | 22 | |||
57 |
Ici, le résultat final 57 / 4 = 14.25
.
Le diviseur 4 est égal à 2 exp 2
. 2 est égal au nombre d'éléments, ici 3,
valeur à laquelle on soustrait 1.
Est-ce que ça fonctionne avec 4 valeurs? Faisons le test:
Charles:
A | B | C | D | |||
---|---|---|---|---|---|---|
16 | 10 | 14 | 11 | |||
13 | 12 | 12.5 | ||||
12.5 | 12.25 | |||||
12.375 |
La valeur Mt est ici 12.375.
Le même tableau, mais avec les sommes:
A | B | C | D | |||
---|---|---|---|---|---|---|
16 | 10 | 14 | 11 | |||
26 | 24 | 25 | ||||
50 | 49 | |||||
99 |
Avec 4 éléments, notre diviseur sera 2 EXP 4-1 = 8
99 / 8 = 12.375
Au passage, on remarquera que 99 est la somme des valeurs 50 et 49, ces valeurs indiquant une légère baisse.
La valeur 50 résulte de l'application de cette formule:
MtX = ( A + 2B + C ) / 4
La valeur 49 résulte de l'application de cette formule:
MtY = ( B + 2C + D ) / 4
La somme Mt, de valeur 99, résulte donc de cette formule:
Mt = ( ( ( A + 2B + C ) / 4 ) + ( ( B + 2C + D ) / 4 ) ) / 2 = ( ( A + 3B + 3C + D ) / 4 ) / 2 = ( A + 3B + 3C + D ) / 8
On retrouve ces facteurs multiplicatifs, pour
( A + 3B + 3C + D ) / 8
,
ici 1 3 3 1
, dans le triangle de Pascal:
Dans le triangle de Pascal, la somme des termes sur la ligne de rang n
(première ligne = rang 0) est égale à 2 EXP n
. C'est cette somme des termes
qui nous sert de diviseur pour calculer la valeur Mt. Exemple, pour le résultat
99, Mt = 99 / ( 1 + 3 + 3 +1 )
, soit 99/8
.
Application en langage FORTH
Ici, vous trouverez le développement, en langage FORTH, du calcul de la moyenne du terrassier. Il y a deux versions, une pour gForth qui traite les données nativement en 32 bits, l'autre pour FlashForth qui utilise une pile 16 bits. Les différences entre ces deux développements aboutissent aux mêmes résultats.
Pour gForth
Spécifique gForth
Le code source complet est disponible ici.
Nous définissons un tableau de n valeurs, ici 5, stockées dans le tableau
initValues
. gForth stocke ces valeurs au format 32 bits:
5 constant nbValues \ number of initials values \ compile initials values create initValues 16 , 10 , 14 , 11 , 18 , \ display values in array : .values ( adr n ---) 0 do dup i cell * + \ calculate address of a value @ cr . \ fetch and display value loop ;
Exemple d'utilisation de .values
. Ce mot affiche n valeurs d'un tableau:
initValues nbValues .values \ display: 16 10 14 11 18 ok
On définit ensuite deux autres tableaux, calcBuffer
qui servira à stocker
les valeurs intermédiaires, finalValues
qui stocke le résultat final:
create calcBuffer nbValues cell * allot create finalValues nbValues cell * allot
Le mot finalToBuffer
copie n valeurs depuis finalValues
vers calcBuffer
:
: finalToBuffer ( n ---)
cell * >r
finalValues calcBuffer r> cmove
;
La variable calcDepth
sert à mémoriser le niveau des calculs a traiter. A chaque
recalcul des moyennes, le contenu de cette variable est décrémenté.
Le mot calcAverage
est chargé de calculer les moyennes intermédiaires. Si le
contenu de la varaible calcDepth
n'est pas égal à un, la fonction se réexcéute
par récursivité:
\ calculate eartworker average variable calcDepth : calcAverage ( ---) -1 calcDepth +! calcDepth @ 0 do calcBuffer i cell * + @ \ get first value in buffer calcBuffer i 1+ cell * + @ + \ get second value in buffer and add finalValues i cell * + ! \ store result loop calcDepth @ 1 > if calcDepth @ finalToBuffer recurse then ;
Le mot calculate
lance une session de calcul de la somme finale
à partir de laquelle on obtiendra la moyenne Mt.
: calculate ( ---) \ move initial values in buffer initValues calcBuffer nbValues cell * cmove \ set initial value of calcDepth nbValues calcDepth ! \ start average calculation calcAverage ;
Pour FlashFORTH
La version FORTH pour Flashforth utilise des données 16 bits. Il a donc été nécessaire de procéder à certains aménagements pour pouvoir traiter les données de même taille que sur gForth, c'est à dire des données 32 bits:
- le mot
2,
aura le même effet que,
sous gForth. - le mot
2offset
permet de calculer le décalage à appliquer à une adresse pour accéder à une donnée 32 bits à partir de l'adresse initiale du tableau. Exemple:
0 2offset
-> 0
1 2offset
-> 4 - le mot
2addr.offset
délivre l'adresse réelle de la donnée de rand n dans un tableau:
addr 0 2offset
-> addr+0
addr 1 2offset
-> addr+4
-average marker -average \ convert integer in double and compile : 2, ( n --- ) s>d swap , , ; \ calculate a 32 bits offset, example: : 2offset ( n --- n' ) cell 2* * ; \ calculate real address for 32 bits content of array, example: : 2addr.offset ( addr offset --- addr' ) 2offset + ;
On retrouve notre tableau des données initiales dans initValues
:
5 constant nbValues \ number of initials values flash \ compile initials values create initValues 16 2, 10 2, 14 2, 11 2, 18 2,
Les mots i
et i+
sont définis pour palier à l'absence
de la boucle do..loop
sous FlashForth:
\ calculate index starting from 0 ram variable startIndex : i ( --- i ) \ create word i that not defined in FlashForth startIndex @ ; : i+ ( ---) \ increment index 1 startIndex +! ;
On retrouve ici le mot .values
où la boucle DO..LOOP
a été remplacé par
une boucle for..next
:
\ display values in array : .values ( adr n ---) 0 startIndex ! for dup \ duplicate initial address i \ get loop index 2addr.offset \ calculate offset in 2array 2@ d. \ fetch and display value i+ next drop ; ram \ calculate eartworker average create calcBuffer nbValues 2offset allot create finalValues nbValues 2offset allot eeprom : finalToBuffer ( n ---) 2offset >r finalValues calcBuffer r> cmove ; ram variable calcDepth eeprom
Puis dans le mot calcAverage
, la récursivité fait place à une boucle
begin..while..repeat
, car sous FlashForth, la profondeur des piles de
données et de retour sont très limitées:
: calcAverage ( ---) begin -1 calcDepth +! 0 startIndex ! calcDepth @ for calcBuffer i 2addr.offset 2@ calcBuffer i 1+ 2addr.offset 2@ d+ finalValues i 2addr.offset 2! i+ next calcDepth @ 1 > while calcDepth @ finalToBuffer repeat ; : calculate ( ---) initValues calcBuffer nbValues 2offset cmove nbValues calcDepth ! calcAverage ;
Résultat de l'execution de calculate
:
initValues nbValues .values cr 16 10 14 11 18 ok<#,ram> calcBuffer 2 .values cr 99 103 ok<#,ram> finalValues 2@ d. cr 202 ok<#,ram>
Analyse du résultat des calculs
Que ce soit pour gForth ou pour FlashForth, pour tester le calcul
de la moyenne du terrassier pour les valeurs stockées dans le tableau initValues
,
il suffit de faire exécuter ces mots comme ceci:
calculate initValues nbValues .values cr calcBuffer 2 .values cr finalValues @ . cr
Affichage de l'exécution sous gForth:
calculate ok ok initValues nbValues .values cr 16 10 14 11 18 ok calcBuffer 2 .values cr 99 103 ok finalValues @ . cr 202 ok
Le mot calculate
lance la séquence de calcul de la moyenne du terrassier.
La séquence initValues nbValues .values cr
affiche les valeurs initiales
contenues dans le tableau initValues
: 16 10 14 11 18
La séquence calcBuffer 2 .values cr
affiche la dernière paire de
valeurs dont la somme sera la valeur à partir de laquelle on calculera la moyenne Mt,
ici 99 103
:
- si la première valeur est inférieure à la seconde, la tendance des données est croissante,
ce qui est le cas ici avec
99 103
; - si la première valeur est supérieur à la seconde, la tendance des données est décroissante;
- si la première valeur est égale à la seconde, la tendance est nulle.
Et enfin, la séquence finalValues @ . cr
affiche la somme finale à partir de laquelle
on peut calculer la moyenne Mt, ici 202
La moyenne MT sera calculée selon la formule 202 / ( 2 EXP nbValues-1)
, soit 202/16
.
A quoi ça peut servir?
C'est une excellente question et je vous remercie de l'avoir posée.
On avait commencé cet article en traitant des notes scolaires pour des élèves; La moyenne Mt n'a, en réalité, aucun intérêt pour traiter des moyennes d'élèves.
Par contre, le calcul de moyenne Mt peut s'avérer très utile dans beaucoup de domaines.
On va prendre un exemple très simple, le cas d'une chaudière de chauffage central qui doit se déclencher si la température d'une sonde descend en dessous de 19°C. Le souci est que cette sonde a tendance à se déclencher de manière intenpestive, ce qui déclenche de nombreux mise en route et arrêt de la chaudière du chauffage central.
L'idée est donc de traiter par moyenne Mt seulement les six dernières mesure de températures, ici des mesures réalisées toutes les 10 minutes:
20 21 20 18 20 20
-> Mt = 625/32 = 19.5312518 20 20 17 18 18
-> Mt = 596/32 = 18.625
Dans le premier cas, bien que la mesure soit transitoirement à 18°C (quatrième valeur), la moyenne Mt étant supérieur à 19, la chaudière ne s'allume pas.
Le second cas correspond aux trois dernières mesures de température de la première ligne, auxquelles
viennent se rajouter le smesures 17 18 18
. La moyenne Mt descend en dessous de
19 et la chaudière s'allumera.
La moyenne Mt s'appliquera donc à un échantillon limité de valeurs. Par exemple, pour suivre l'évolution de ventes de produits sur une semaine, on prendra les 7 dernières valeurs de vente. Si chaque jour, on récupère les chiffres sur 7 jours glissants, il sera possible d'obtenir une tendance à la baisse, à la hausse ou aucune tendance d'évolution de ces ventes.
Pour conclure, nous avons traité, pour gForth et FlashForth des données entières au format 32 bits. Le calcul Mt fonctionne aussi avec des valeurs négatives. Si votre version du langage Forth dispose des fonctions de calcul en virgule flottante, libre à vous d'adapter le code Forth.