Station météo : températures négatives et flottants
Une station météo autonome relève la température toutes les dix minutes et la stocke dans un fichier binaire, sur un octet signé en complément à deux. Les températures attendues vont de -40 °C à +50 °C. La carte mémoire ne permet pas de passer à deux octets par mesure. Le programme de lecture fait valeur = octet sans conversion, puis affiche parfois 216 au lieu de -40. Un stagiaire ajoute un calcul de moyenne glissante avec moyenne = (t1 + t2) / 2 et obtient 12.299999999999999 au lieu de 12.3. Il propose de comparer les températures avec == et de stocker les moyennes en float. Le responsable craint aussi qu'un capteur défaillant envoie 140 et fasse écrire une valeur incorrecte dans le fichier. Le fichier contient déjà 52 000 mesures et doit rester compact.
1. Expliquer comment l'octet 11011000 est interprété comme -40 en complément à deux, donner l'encodage de +50, et préciser la plage représentable. Pourquoi 216 apparaît-il à l'affichage ?
Read the worked answer
En complément à deux sur 8 bits, le bit de poids fort vaut -128. Pour -40 : on écrit 40 en binaire sur 8 bits, 0010 1000 ; on inverse les bits, 1101 0111 ; on ajoute 1, 1101 1000, soit 216 en non signé. L'affichage de 216 vient de la lecture non signée : le programme interprète l'octet comme un entier de 0 à 255 au lieu de -128 à 127. Pour +50 : 0011 0010. La plage est -128 à +127, donc -40 et +50 sont représentables. La valeur 140 n'est pas représentable : 140 s'écrit 1000 1100 en binaire non signé, mais en complément à deux ce motif vaut -116. Il y a donc un risque de mesure faussement négative.
2. Expliquer l'origine de 12.299999999999999 et proposer deux façons correctes de tester l'égalité ou d'arrondir. Pourquoi stocker les températures en float ne résout-il pas le problème de fond ?
Read the worked answer
0.1 et 0.2 n'ont pas d'écriture binaire finie en base 2 ; 0.1 vaut environ 0.1000000000000000055, et leur somme n'est pas exactement 0.3. Le résultat 12.299999999999999 est la représentation la plus proche. Tester == est donc fragile. Deux méthodes : comparer avec une tolérance, abs(a - b) < 1e-9 ; ou arrondir au nombre de décimales utiles, round(x, 1) == 12.3. Pour des températures au dixième, on peut aussi stocker des dixièmes de degré en entiers (123 pour 12,3), ce qui rend les calculs exacts tant qu'on reste dans la plage. Passer à float ne résout pas le problème de fond : les flottants binaires ne représentent pas exactement les décimaux, et les erreurs s'accumulent.
3. Le capteur envoie 140. Que se passe-t-il si on l'écrit quand même sur un octet signé ? Proposer un contrôle et un codage d'erreur sans agrandir le format.
Read the worked answer
Si on écrit 140 sur un octet signé, le motif binaire 1000 1100 est relu comme -116 : le fichier contient une valeur plausible mais fausse. Il faut valider avant écriture : if not (-40 <= t <= 50): refuser. Comme la plage utile est -40 à +50, on peut réserver une valeur sentinelle, par exemple -128, pour coder « capteur en erreur », sans changer le format. Il faut aussi documenter ce codage et vérifier à la lecture. Une autre solution serait de stocker la température en dixièmes dans un entier signé, mais la plage -400 à 500 ne tient pas sur 8 bits : il faudrait 16 bits, ce que la carte mémoire ne permet pas.