Objectifs pédagogiques
Les principaux objectifs de cette feuille d'exercices sont :
- de diversifier la gamme des types utilisés (en particulier les types entiers à largeur spécifiée du langage C) ;
- de découvrir les opérateurs de calcul sur les mots binaires (opérateurs logiques bits à bits, opérateurs de décalage de bits) ;
- d'approfondir l'usage des fonctions d'entrées-sorties standards.
Pour traiter ces exercices, il est recommandé d'avoir étudié le cours jusqu'au chapitre C3‑IX inclus (à l'exception du chap. C3‑IV). Néanmoins, certains exercices ne font appel qu'à un nombre ciblé de connaissances et des renvois aux principaux éléments de cours requis sont indiqués au fur et à mesure des questions.
Travail demandé
Les exercices sont presque tous indépendants les uns des autres, mais ordonnés par niveaux croissants de difficultés et de connaissances requises.
Pour coder les programmes, il est vivement recommandé d'utiliser un IDE comme VS Code, à paramétrer pour obtenir une coloration syntaxique adaptée au langage C++ (cf. chap. C2‑X ).
- Au fur et à mesure, enregistrer chaque fichier source principal en le nommant conformément à la numérotation des exercices, c'est‑à‑dire par exemple :
C3exoNvX.ino
où N est le numéro de l'exercice et X la version du programme. - Pour chaque exercice, tous les fichiers, y compris les exécutables générés par la chaîne de compilation locale, doivent être regroupés dans un répertoire de projet, lui‑même placé dans un répertoire d'exercices nommé par exemple
C3_EXOS, lui‑même placé dans le répertoire principal de programmation, lui‑même placé dans répertoire personnel d'étudiant.
Remarque. L'exercice nº 5 est en relation avec le sujet de TP nº C3‑1.
- Limites d'encodage des types entiers et décimaux standards
- Tester d'abord ce programme dans l'environnement OnlineGDB en langage C puis en C++17. Effectuer également la compilation avec GCC sous Linux.
- Tester ce programme sous Windows avec la chaîne de compilation MinGW. Que constate‑t‑on ?
- * Dans le même esprit, coder un programme qui affiche les limites d'encodage des types décimaux standards (
float,double,long double), en utilisant les pseudo‑constantes définies dans le fichier d'en‑têtefloat.hde la bibliothèque standard du langage C (cf. chap. C3‑V ). Avec les spécifications de conversion adaptées aux types flottants (cf. chap. C3‑V ), et en sélectionnant la version du langage appropriée (cf. chap. C3‑V ), on doit obtenir une exécution produisant en sortie standard l'affichage ci‑dessous. - Génération de nombres aléatoires et statistiques
- on simule un grand nombre de lancés d'un dé à 6 faces (six‑sided dice – ou die) ;
- ce faisant, on calcule les deux principaux paramètres statistiques de l'ensemble des résultats obtenus : la moyenne et l'écart‑type ;
- pour finir, on calcule pour chacun de ses deux paramètres, la différence avec la valeur de la grandeur probabiliste correspondante, sachant qu'un dé supposé parfait suit une loi de probabilité uniforme discrète – cf. la page Wikipedia W. Il est indispensable de consulter cette page web (ou une documentation équivalente) pour connaître les valeurs de ces grandeurs probabilistes :
- l'espérance qui correspond à la moyenne ;
- la racine carrée de la variance qui correspond à l'écart‑type.
- Coder un programme qui simule
NB_OF_ROLLSlancés du dé (à l'aide des fonctionsrandetsrand– cf. chap. C3‑II ), qui calcule la moyenne statistique des résultats obtenus et qui compare (c'est‑à‑dire, calcule la différence – en anglais, gap) avec l'espérance mathématique de la loi uniforme discrète donnée via le lien supra (c'est‑à‑dire, la valeur théorique de la moyenne pour un nombre infini de lancés). - Au programme précédent, ajouter le calcul de l'écart‑type W des résultats obtenus. Pour cela, On utilisera non pas la formule de définition de l'écart‑type, mais la propriété donnée par la formule en figure ci‑contre. Calculer la différence (gap) avec la racine carrée de la variance de la loi uniforme discrète (c'est‑à‑dire, la valeur théorique de l'écart‑type pour un nombre infini de lancés).
- Au programme précédent, ajouter un calcul du déséquilibre de la population des lancés par rapport à la valeur théorique de la médiane W, c'est‑à‑dire la différence entre le nombre de valeurs inférieures et le nombre de valeurs supérieures à la valeur théorique de la médiane, rapportée au nombre de lancés.
- Calculateur d'adresses IPv4
- le masque du réseau,
- l'adresse du réseau,
- la première adresse de machine,
- la dernière adresse de machine,
- l'adresse de diffusion générale (broadcast),
- et le nombre total d'adresses de machines qu'on peut attribuer sur ce réseau.
- Les cinq composantes de l'adresse saisie par l'utilisateur seront récupérées via la fonction
scanfsous forme d'octets, c'est‑à‑dire de variables de typeuint8_tdéclarées respectivementipByte3,ipByte2,ipByte1,ipByte0par ordre de poids décroissants etipMaskpour la valeur CIDR du masque. Il faut employer les spécifications de conversion appropriées (cf. chap. C2-VI ). - À partir des octets de l'adresse saisie, les six adresses à déterminer seront calculées dans des variables de type
uint32_trespectivement déclaréeshostIPaddress,netIPmask,netIPaddress,firstIPaddress,lastIPaddressetbroadcastIPaddress. - Encodage de caractères Unicode en UTF‑8
- en notation hexadécimale ;
- sous forme de caractères ASCII étendus dans la page de code Windows‑CP1252 (cf. chap. C3‑VIII ), comme sur l'affiche parodique ci‑contre où le caractère attendu « é » est remplacé par la séquence d'octets affichée
é. - sur un PC Windows avec la chaîne de compilation MinGW32 (l'ancienne version 32 bits ne prend pas en charge l'UTF‑8).
- sur un PC Linux avec la chaîne de compilation GCC, à condition de changer l'encodage des caractères dans le terminal de commandes en ligne (cf. chap. C3‑VIII ).
- Le point de code Unicode saisi par l'utilisateur sera enregistré dans une variable déclarée
unicodePointde typeuint32_t. - Le ou les octets du code UTF‑8 à déterminer seront mémorisés dans une variable de type tableau de
uint8_tnomméeutf8code. - Pour faciliter le codage des opérations sur les bits de ces octets, on pourra copier‑coller en début de programme le code source des pseudo‑fonctions
bitRead,bitSet,bitClearetbitWriteissu du fichier d'en‑tête de bibliothèqueArduino.hG (cf. chap. C3‑III . - Simulation de la fonction de transfert du CAN d'une carte Arduino Uno
-
MAX_VOLTAGEpour la valeur maximale sur l'échelle de la tension entrée (5 V) ; -
MAX_NUMBERpour la valeur maximale de l'excursion du nombre en sortie (1023) ; -
QUANTUMpour le quantum de conversion, défini en fonction des deux constantes précédentes (cf. cours). - Coder un programme qui, en boucle, calcule la valeur du nombre en sortie Ns théoriquement rendu par la fonction de transfert du CAN pour une valeur de la tension d'entrée ve saisie par l'utilisateur. On prendra la valeur
0comme condition de fin d'itération de la boucle. - Coder un programme qui détermine les valeurs de la tension d'entrée aux seuils des marches et la longueur des marches de la courbe en escalier du CAN. Pour cela :
- coder une boucle
fordont la variable d'incrémentation simule une tension d'entrée ve croissante par pas de 0,0001 V sur l'intervalle 0 – 5 V ; - dans cette boucle, calculer le nombre en sortie Ns et le comparer avec sa valeur précédente ; en cas de différence (détection d'un seuil), calculer le nombre de quanta que représente la tension d'entrée (ce nombre permet très facilement de déduire la longueur de la marche précédent le seuil).
- Dans le contexte d'implémentation d'un bargraphe (cf. TP C3‑2 ), on souhaite que les seuils d'allumage des led successives sont conformes aux valeurs numériques du nombre en sortie Ns inscrites en noir sur la figure ci‑contre.
- calculer à partir de Ns le nombre courant de led à allumer et mémoriser sa valeur dans une variable déclarée
currentLitLedNumber; - comparer la valeur de
currentLitLedNumberavec sa valeur précédente (en utilisant une variable déclaréepreviousLitLedNumber) pour détecter les seuils d'allumage des led du bargraphe.
Coder un programme qui affiche les limites d'encodage des types entiers standards, en utilisant non pas des valeurs numériques mais les pseudo‑constantes définies dans le fichier d'en‑tête limits.h de la bibliothèque standard du langage C (cf. chap. C3‑II ). Sous Linux, on doit obtenir une exécution produisant en sortie standard l'affichage ci‑dessous (sous Windows, les valeurs pour les types long sont différentes).
TYPE DESCRIPTOR | MIN. VALUE | MAX. VALUE
char | -128 | 127
unsigned char | 0 | 255
short | -32768 | 32767
unsigned short | 0 | 65535
int | -2147483648 | 2147483647
unsigned int | 0 | 4294967295
long | -9223372036854775808 | 9223372036854775807
unsigned long | 0 | 18446744073709551615
long long | -9223372036854775808 | 9223372036854775807
unsigned long long | 0 | 18446744073709551615
Pour la première ligne du tableau, on pourra coder l'instruction suivante (cf. chap. C2‑VII ) :
printf(" %18s | %20s | %20s \n", "TYPE DESCRIPTOR", "MIN. VALUE", "MAX. VALUE");
et pour les lignes suivantes, on reprendra alors la même chaîne de format en adaptant les spécifications de conversions (cf. chap. C2‑VII ) en fonction des types des arguments à afficher. Par exemple, pour le type char, on codera :
printf(" %18s | %20d | %20d \n", "char", CHAR_MIN, CHAR_MAX);
TYPE DESCRIPTOR | DENORM. MIN. VALUE | NORM. MIN. VALUE | MAX. VALUE
float | 1.4e-45 | 1.2e-38 | 3.4e+38
double | 4.9e-324 | 2.2e-308 | 1.8e+308
long double | 3.6e-4951 | 3.4e-4932 | 1.2e+4932
On souhaite tester la qualité du générateur de nombres pseudo‑aléatoires employé par un ordinateur. Pour cela :
On déclarera une constante nommée NB_OF_ROLLS pour coder le nombre de lancés du dé et on lui donnera successivement les valeurs 10, 1000 et 1000000 pour tester le programme.
>>>>> Random number generation test program <<<<< Number of rolls: 1000 -------------------------------------- Statistical mean: 3.496 Math expectation: 3.5 Gap: -0.004
-------------------------------------- Standard deviation: 1.76182 Variance square root: 1.70783 Gap: 0.0539921
-------------------------------------- Median unbalance: -0.8 % (expected 0 %)
On souhaite coder un calculateur d'adresses IPv4 à l'instar de ceux que l'on peut trouver sur l'Internet (cf. la capture d'écran ci‑contre). À partir d'une adresse saisie par l'utilisateur en notation décimale pointée CIDR (cf. chap. R1‑III R), c'est‑à‑dire de la forme :
▯▯▯.▯▯▯.▯▯▯.▯▯▯/▯▯
le programme doit déterminer la valeur entière de cette adresse IP puis calculer toutes les adresses nécessaires en notation décimale pointée :
Pour tout rappel sur ces notions, on peut se reporter au chapitre R1‑III R.
On peut tester le bon fonctionnement du programme avec des adresses diverses en comparant les résultats avec ceux obtenus par un calculateur en ligne comme celui dont le lien est donné supra.
On souhaite coder un programme qui, en boucle, détermine l'encodage UTF‑8 (cf. chap. C3‑IX ) d'un caractère à partir de son numéro – ou point de code hexadécimal – dans le catalogue Unicode (cf. chap. C3‑IX ), saisi par l'utilisateur. On demande deux formats d'affichage des octets du code UTF‑8 :
Attention : pour arriver à produire l'effet attendu, deux solutions sont possibles pour compiler et exécuter le programme :
Les tests de « bon » fonctionnement seront effectués successivement pour les 4 caractères listés dans le tableau ci‑dessous.
| Glyphe | A | é | ₿ | 😈 |
|---|---|---|---|---|
Point de code (0x) |
U+41 | U+E9 | U+20BF | U+1F608 |
Code UTF-8 (0x) |
41 |
C3 A9 |
E2 82 BF |
F0 9F 98 88 |
| Code UTF-8 (CP1252 ) | A |
à © |
â ‚ ¿ |
ð Ÿ ˜ ˆ |
Typiquement, on doit obtenir un affichage comme, par exemple :
>>>>> Unicode to UTF-8 Program <<<<< Type 0 to EXIT or type an hexadecimal Unicode point: U+41 UTF-8 code = 41 (A) type an hexadecimal Unicode point: U+E9 UTF-8 code = C3 A9 (Ã ©) type an hexadecimal Unicode point: U+20BF UTF-8 code = E2 82 BF (â ‚ ¿)
En fin d'exécution (lorsque l'utilisateur décide d'arrêter, via la saisie du code 0), le programme devra afficher la phrase titre du livre en vignette ci‑dessus, avec l'erreur de transcodage :
martine écrit en UTF-8
En théorie, le convertisseur analogique numérique (CAN) du microcontrôleur embarqué sur une carte Arduino Uno opère une conversion linéaire centrée unipolaire. À pleine échelle, sa fonction de transfert admet donc une courbe représentative dite « en escalier », avec des marches de longueur constante sauf la première et la dernière (cf. la figure ci‑contre et le chap. C3‑VII pour plus de détails).
On souhaite coder un programme de simulation de cette fonction de transfert pour pouvoir ensuite tester diverses fonctions de mise à l'échelle (par exemple, celle utilisée pour un bargraphe).
On déclarera au début de la fonction main des constantes mémorisant les principales caractéristiques du CAN :
| ve | 5 |
4.990 |
2.5 |
1 |
0.0025 |
0.0024 |
0 |
|---|---|---|---|---|---|---|---|
| Ns | 1023 |
1022 |
512 |
205 |
1 |
0 |
0 |
>>>>> Arduino Uno ADC transfer function simulation <<<<<
Number | Voltage | Quanta
1 | 0.0025 | 0.5
2 | 0.0074 | 1.5
3 | 0.0123 | 2.5
1021 | 4.9830 | 1020.5
1022 | 4.9878 | 1021.5
1023 | 4.9927 | 1022.5
for d'incrémentation de la tension d'entrée ve : map (cf. chap. C2‑IV ) en récupérant son code source dans le fichier WMath.cpp G ;
>>>>> Bargraph transfer function simulation <<<<<
ADC Number | LED
64 | 1
192 | 2
320 | 3
448 | 4
576 | 5
704 | 6
832 | 7
960 | 8