32 44
… quand l’informatique s’emmêle les bits
Un système de numération permet de compter des objets et de les représenter par des nombres. Un système de numération positionnel possède trois éléments :
Base \(b\) (un entier supérieur à 1)
Symboles (digits) : 0, 1, 2, …, \(b-1\)
Poids des symboles selon la position et la base, où poids=baseposition
Le système positionnel utilise la représentation polynomiale. Celle-ci est donnée par:
\[ \begin{aligned} (a_na_{n-1}\cdots a_1a_0,a_{-1}a_{-2}\cdots a_{-m})_b &= \sum_{k=-m}^n a_k b^k \end{aligned} \]
où \(b\) est la base et les \(a_i\) sont des coefficients (les symboles de votre système de numération).
Base = 2
Symboles ordonnés qu’on nomme les chiffres : 0, 1.
Le poids des symboles est donné par 2position
Par exemple:
\[ \begin{align} (1 \ 0100\ 1111)_2 &= 1\cdot 2^8 + 1\cdot 2^6 + 1\cdot 2^3 + 1\cdot 2^2 + \\ & \qquad + 1\cdot 2^1 + 1\cdot 2^0 \\ &= (335)_{10} \end{align} \]
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 10
\[ \begin{array}{ccccccc} & & & \tiny{1} & & \tiny{1} & \\ & 1 & 0 & 0 & 1 & 0 & 1 \\ + & & 1 & 0 & 1 & 0 & 1 \\ \hline & 1 & 1 & 1 & 0 & 1 & 0 \\ \end{array} \]
Les ordinateurs utilisent des bits pour emmagasiner de l’information.
Un bit peut prendre la valeur 0 ou la valeur 1.
L’information est emmagasinée dans des trains de bits (\(T_n\)) de longueur \(n\) (une succession de \(n\) bits).
\(T_4 = 0110\)
Dans la majorité des langages informatiques, les trains de bits ont une longueur prédéterminée, qu’il est impossible de dépasser.
En Python
, contrairement à la plupart des langages informatiques, les entiers sont représentés avec une précision infinie. C’est-à-dire que la seule limite correspond à la mémoire interne de la machine que vous utilisez.
Par exemple, \(2^{32}\) est représenté en utilisant 32 bits et \(2^{128}\) est représenté en utilisant 44 bits.
Entiers non signés
La représentation binaire non signée sur \(n\) bits d’un entier \(x\) est le train de bits correspondant à l’écriture de \(x\) en base 2.
Par exemple, en utilisant 8 bits:
L’entier maximal pouvant être représenté correspond au train de bits de longueur \(n\) composé uniquement de 1.
\[ \text{Entier maximal} = \sum_{k=0}^{n-1} 1 \cdot 2^k = 2^n-1 \]
Par exemple, en utilisant 8 bits:
import numpy as np
aggressivite = np.array(1).astype('uint8')
democratie = np.array(2).astype('uint8')
print(aggressivite-democratie)
255
“It is true that Gandhi would—eventually—use nukes when India was at war, just like any civilization in the game, and at the time this did strike a lot of players as odd,”
“It’s also true that Gandhi would frequently threaten the player, because one of his primary traits was to avoid war, and deterrence through mutually assured destruction was an effective way to go about that.”
Pour garder le compte des trains sur le réseau ferroviaire suisse, des détecteurs sont placés sur les rails.
Ces détecteurs comptent le nombre d’essieus de chaque train.
Ils utilisent un entier non signé sur 8 bits.
Si un train avait exactement 256 essieus, le compteur retournerait à zéro, et ce train deviendrait indétectable… un train fantôme.
Le passage précédent se traduit par “Pour éviter de faussement signaler une section de rails comme étant vide, en remettant le compteur à zéro, le nombre total d’essieus d’un train ne doit pas être égal à 256”.
Therac-25 était le nom d’une machine de radiothérapie développée conjointement par l’Énergie atomique du Canada Limitée et CGR MeV.
Entre 1985 et 1987, le Therac-25 fut impliqué dans au moins six accidents durant lesquels des patients reçurent des doses massives de radiation, parfois de l’ordre de plusieurs centaines de grays.
Au moins cinq patients décédèrent des suites de l’irradiation.
Doses | Effets |
---|---|
20 Gy | Mort instantanée |
10 Gy | Mort pratiquement certaine |
5 Gy | Dose tuant 50% des sujets exposés |
La machine ne possédait pas de dispositif physique pour bloquer le flux d’électrons en mode « haute énergie » si la cible n’était pas en place.
Le logiciel utilisait un fanion sur 8 bits et l’incrémentait, plutôt que d’utiliser un booléen (True
ou False
)
Des dépassements de capacité se produisaient et engendraient la désactivation de certains tests de sécurité.
Entiers signés
La représentation binaire signée sur \(n\) bits d’un entier est le train de bit où le premier bit de gauche représente le signe (positif si le bit est 0 et négatif si le bit est 1), et où les \(n-1\) bits restants représentent l’écriture de \(|x|\) en base 2.
Par exemple sur huit bits:
Entiers signés
La représentation binaire signée sur \(n\) bits d’un entier est le train de bit où le premier bit de gauche représente le signe (positif si le bit est 0 et négatif si le bit est 1), et où les \(n-1\) bits restants représentent l’écriture de \(|x|\) en base 2.
Par exemple sur huit bits:
\[\begin{gather} \text{Entier maximal} = 2^{n-1}-1 \\ \text{Entier minimal} = -(2^{n-1}-1) \end{gather}\]
Par exemple, en utilisant 8 bits:
\[\begin{gather} \text{Entier maximal} = 2^{n-1}-1 \\ \text{Entier minimal} = -(2^{n-1}-1) \end{gather}\]
Par exemple, en utilisant 8 bits:
La bonne réponse est 52!!!
Les nombres positifs sont représentés de manière usuelle.
Les nombres négatifs sont obtenus en calculant l’opposé du nombre positif par deux opérations successives:
On inverse les bits de l’écriture binaire (les 0 deviennents des 1 et vice-versa);
On ajoute 1 au résultat (les dépassements sont ignorés).
Cette opération correspond au calcul de \(2^n-|x|\).
Valeur réelle Valeur signée
125 125
126 126
127 127
128 -128
129 -127
130 -126
\[ 5\ 319\ 511\ 278 \]
Extra, Extra - Read All About It: Nearly All Binary Searches and Mergesorts are Broken
Une erreur dans le code pour la routine binarySearch
est restée introuvable durant neuf ans.
public static int binarySearch(int[] a, int key) {
int low = 0;
int high = a.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
int midVal = a[mid];
if (midVal < key)
low = mid + 1
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
Les entiers dans Java
sont codés sur 32 bits.
Le bug apparaît si la somme de low
et high
est plus grande que la valeur maximum possible pour un entier signé dans Java
, \(2^{31}-1\).
La somme déborde en une valeur négative, et la valeur reste négative lorsque divisée par deux.
Le bogue peut apparaître pour des vecteurs de longueurs (en nombre d’éléments) \(2^{30}\) ou plus (environ un milliard d’éléments). De tels vecteurs étaient impensables dans les années 1980 lorsque le code a été écrit.
Python
:public static int binarySearch(int[] a, int key) {
int low = 0;
int high = a.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
int midVal = a[mid];
if (midVal < key)
low = mid + 1
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
public static int binarySearch(int[] a, int key) {
int low = 0;
int high = a.length - 1;
while (low <= high) {
int mid = low + ((high - low) / 2);
int midVal = a[mid];
if (midVal < key)
low = mid + 1
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
Python
:celui de l’an 2038
Le nombre de secondes écoulées depuis le 1er janvier 1970 00:00:00 UTC, hors secondes intercalaires.
Une seconde intercalaire, est un procédé employé pour ajuster le temps universel coordonné (UTC), au temps solaire.
Sur les ordinateurs fonctionnant sur 32 bits, la plupart des systèmes d’exploitation concernés représentent ce nombre comme un nombre entier signé de 32 bits, ce qui limite le nombre de secondes à \(2^{31}-1\).
\(2^{31}-1\) secondes correspond à 2 147 483 647 secondes.
Ce nombre sera atteint le 19 janvier 2038 à 3 h 14 min 7 s (UTC).
La seconde suivante, représente −2 147 483 648 en complément à deux, soit plus de 2 milliards de secondes avant 1970, le 13 décembre 1901 à 20 h 45 min 52 s pour être précis.
La solution est de passer à un horodatage sur 64 bits.
Le nombre de secondes possible serait maintenant de \(2^{63}-1\), ce qui correspond à 9 223 372 036 854 775 807 secondes!
La date butoir se retrouverait le dimanche 4 décembre 292 277 026 596 après J.-C. à 15 h 30 min 8 s.
Environ 21 fois l’âge de l’univers.
“To keep a Boeing Dreamliner flying, reboot once every 248 days.”
“… a Model 787 airplane that has been powered continuously for 248 days can lose all alternating current (AC) electrical power due to the generator control units (GCUs) simultaneously going into failsafe mode,”
“This condition is caused by a software counter internal to the GCUs that will overflow after 248 days of continuous power. We are issuing this AD to prevent loss of all AC electrical power, which could result in loss of control of the airplane.”
Le temps écoulé depuis le démarrage du système est compté en centièmes de secondes.
Ce temps est stocké dans un entier signé de 32 bits.
Le nombre maximal possible est \(2^{31}-1\) centièmes de secondes.
Ça correspond à \(\frac{2^{31}-1}{100 \cdot 60 \cdot 60 \cdot 24}=\) 248.551348 jours…
Le format TrueType
de fonte numérique utilise un nombre signé à virgule fixe de 32 bits, avec 26 bits pour la partie entière.
Le premier Playstation
utilisait un nombre à virgule fixe de 16 bits, avec 12 bits pour la partie fractionnaire.
\(\LaTeX\) utilise un nombre à virgule fixe signé de 32 bits, avec 16 bits pour la partie fractionnaire, pour calculer les positions des objets. Pour les fontes, \(\LaTeX\) utilise un nombre à virgule fixe signé de 32 bits, avec 12 bits pour la partie fractionnaire.
Le 25 février 1991, un Scud irakien frappait les casernes de Dhahran, en Arabie saoudite, tuant 28 soldats du centre de commandement du 14e détachement de l’armée des États-Unis.
Une recherche gouvernementale a indiqué que l’interception manquée de Dharan avait été provoquée par une erreur de logiciel dans son système de coordination.
La batterie de missiles Patriot de Dharan se trouvait alors en fonction depuis plus de 100 heures or, avec le temps, des erreurs apparaissaient dans le système et décalaient la position perçue de la cible avec sa position réelle.
Le temps était mesuré en dixièmes \(\left(\frac{1}{10}\right)\) de secondes.
Le temps était conservé dans un nombre à virgule fixe, avec 24 bits pour la partie fractionnaire.
Malheureusement, \(\frac{1}{10}\) a une représentation infinie en binaire.
\[ \frac{1}{10} = \frac{3}{32}\sum_{k=0}^{\infty} \left( \frac{1}{16} \right)^k = 0,0\ 0011\ 0011\ 0011\ 0011\ \ldots \]
\[ 0,0\ 0011\ 0011\ 0011\ 0011\ 0011\ 00\ldots \]
Après 100 heures, nous avons une erreur de:
\[ \frac{1}{10 \cdot 16^5} \cdot 10\cdot 100\cdot 60\cdot 60 \approx 0,342\ \text{secondes} \]
Les missiles Scud que les Patriot devaient intercepter voyageaient à une vitesse de 1 676 mètres par secondes…
Ils parcouraient donc environ 573 mètres durant le laps de temps de l’erreur.
Les Scud étaient détectés, mais les Patriot les rataient.
\[ +13,254 = \underbrace{+}_{\text{signe}} 0,\underbrace{13254}_{\text{mantisse}} \times 10^{\overbrace{{2}}^{\text{exposant}}} \]
\[ +10,101 = \underbrace{+}_{\text{signe}} \overbrace{1}^{\text{toujours}\ 1},\underbrace{0101}_{\text{mantisse}} \times 2^{\overbrace{{1}}^{\text{exposant}}} \]
Un nombre flottant normalisé a une valeur \(N\) donnée par la formule suivante: \[ N = S \times 2^{E-\text{BIAIS}} \times \left(1+\frac{M}{2^m}\right) \]
Le nombre maximum représentable est :
\[ 1,7976931348623157 × 10^{308} \]
Le code problématique:
L_M_BV_32 := TBD.T_ENTIER_16S((1.0 / C_M_LSB_BH) *
G_M_INFO_DERIVE(T_ALG.E_BH));
if L_M_BV_32 > 32767 then
P_M_DERIVE(T_ALG.E_BV) := 16#7FFF#;
elseif L_M_BV_32 < -32768 then
P_M_DERIVE(T_ALG.E_BV) := 16#8000#;
else
P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS(TBD.T_ENTIER_16S(L_M_BV_32));
end if;
P_M_DERIVE(T_ALG.E_BH) := UC_16S_EN_16NS(TBD.T_ENTIER_16S
((1.0 / C_M_LSB_BH) *
G_M_INFO_DERIVE(T_ALG.E_BH));
Le cas de l’accélération verticale est évalué correctement.
L_M_BV_32 := TBD.T_ENTIER_16S((1.0 / C_M_LSB_BH) *
G_M_INFO_DERIVE(T_ALG.E_BH));
if L_M_BV_32 > 32767 then
P_M_DERIVE(T_ALG.E_BV) := 16#7FFF#;
elseif L_M_BV_32 < -32768 then
P_M_DERIVE(T_ALG.E_BV) := 16#8000#;
else
P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS(TBD.T_ENTIER_16S(L_M_BV_32));
end if;
P_M_DERIVE(T_ALG.E_BH) := UC_16S_EN_16NS(TBD.T_ENTIER_16S
((1.0 / C_M_LSB_BH) *
G_M_INFO_DERIVE(T_ALG.E_BH));
Le cas de l’accélération horizontale ne l’est pas…
L_M_BV_32 := TBD.T_ENTIER_16S((1.0 / C_M_LSB_BH) *
G_M_INFO_DERIVE(T_ALG.E_BH));
if L_M_BV_32 > 32767 then
P_M_DERIVE(T_ALG.E_BV) := 16#7FFF#;
elseif L_M_BV_32 < -32768 then
P_M_DERIVE(T_ALG.E_BV) := 16#8000#;
else
P_M_DERIVE(T_ALG.E_BV) := UC_16S_EN_16NS(TBD.T_ENTIER_16S(L_M_BV_32));
end if;
P_M_DERIVE(T_ALG.E_BH) := UC_16S_EN_16NS(TBD.T_ENTIER_16S
((1.0 / C_M_LSB_BH) *
G_M_INFO_DERIVE(T_ALG.E_BH));
desautm.github.io/math-catastrophe