Vous êtes sur la page 1sur 9

UE 2A005 Version enseignant Examen 2016-2017 – page 1/9

Examen 2016-2017 : correction

Vendredi 19 mai 2017 – Durée : 2 heures.


Sans document.

— Coller le numéro d’anonymat sur chacun des livrets.


— Ne pas dégrafer le sujet, ni détacher le memento FORTRAN.
— Les calculatrices, baladeurs et autres appareils électroniques sont interdits.
— Les téléphones portables doivent être éteints et rangés dans les sacs.
— Les sacs et manteaux doivent être déposés en bas de l’amphithéâtre pendant l’examen.
— Cet énoncé contient 9 pages.
— Répondre directement sur le sujet dans les cadres prévus à cet effet.
— Lire la totalité du sujet avant de commencer. Les questions sont en grande partie indépendantes.

— En cas de manque de place, des cadres supplémentaires sont disponibles en page 7 pour la partie 1, et en
page 14 pour la partie 2.
— Le memento FORTRAN figure en fin de premier et deuxième livret pages 8, 15 et 16.

Exercice 1 – Questions de cours (∼ 15 min)

1. Parmi les instructions suivantes, cocher celles qui permettent de générer aléatoirement un entier compris entre 1 et 6
au sens large, avec la même probabilité. La variable r est déclarée réelle, la variable e entière.

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 2/9

CALL RANDOM NUMBER (r)


 e = 6*r + 1

CALL RANDOM NUMBER (6*r)


 e = FLOOR(r) + 1

CALL RANDOM NUMBER (r)


 e = NINT(5*r+1)

CALL RANDOM NUMBER (r)


 e = 6*FLOOR(r)+1

CALL RANDOM NUMBER (r)


 e = CEILING(6*r)

CALL RANDOM NUMBER (r)


 e = FLOOR(6*r)

Solution :
Les réponses 1 et 5 sont valides.

2. Le code suivant doit créer un tableau dynamique de n réels, n étant saisi par l’utilisateur, puis demander d’en saisir
le contenu et l’afficher. Trouver 5 erreurs ou oublis (penser aux bonnes pratiques liées à l’allocation dynamique).
Corriger les lignes correspondantes dans le cadre de droite, sans récrire la totalité du code.
PROGRAM cinq_erreurs
IMPLICIT NONE
PROGRAM cinq_erreurs
INTEGER :: n, ok
IMPLICIT NONE
! Erreur 1 : ALLOCATABLE
INTEGER :: n, ok
REAL, DIMENSION(:), ALLOCATABLE :: tab
REAL, DIMENSION(:) :: tab
! Erreur 2 : saisie d’abord
PRINT *, "Saisir la taille n"
ALLOCATE(tab(n), IOSTAT=ok)
READ *, n
! Erreur 3 : STAT et pas IOSTAT
PRINT *, "Saisir la taille n"
ALLOCATE(tab(n), STAT=ok)
READ *, n
! Oubli 4 : Test allocation
IF (ok /= 0) STOP "probleme allocation"
PRINT *, "Saisir le tableau"
PRINT *, "Saisir le tableau"
READ *, tab
READ *, tab
PRINT *, "Le tableau est :"
PRINT *, "Le tableau est :"
PRINT *, tab
PRINT *, tab
! Oubli 5 : Desallocation
END PROGRAM cinq_erreurs
DEALLOCATE(tab)
END PROGRAM cinq_erreurs

Exercice 2 – Election présidentielle (∼ 45 min)


On dispose d’un fichier de données appelé election_pres.dat qui contient, en premier enregistrement, le nombre
de candidats au premier tour de l’élection présidentielle de 2017, puis, dans les enregistrements suivants, le nom de
chaque candidat suivi du nombre de voix obtenues. En voici les premiers enregistrements :

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 3/9

11
ARTHAUD Nathalie 232428
ASSELINEAU Francois 332588
CHEMINADE Jacques 65598
DUPONT-AIGNAN Nicolas 1695186
...

On écrit un programme permettant d’afficher le classement des candidats et le pourcentage des voix exprimées qui se
sont portées sur eux.
1. Le programme a été commencé et le listing disponible est affiché ci-dessous. Le compléter aux endroits indiqués par
des lignes horizontales : _________.

Solution :
MODULE mod_election
IMPLICIT NONE

CONTAINS
SUBROUTINE lecture_fichier(nom_fichier, nom_cand, nb_voix)
CHARACTER(LEN=*), INTENT(IN) :: nom_fichier
CHARACTER(LEN=22), DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: nom_cand
INTEGER, DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: nb_voix

INTEGER :: nb_cand, ok, i

OPEN(UNIT=10, FILE=TRIM(nom_fichier), STATUS=’old’, IOSTAT=ok)


IF (ok/=0) STOP "Probleme lecture fichier"

READ(UNIT=10, FMT=*) nb_cand

ALLOCATE(nom_cand(nb_cand), nb_voix(nb_cand), STAT=ok)


IF (ok/=0) STOP "Probleme allocation"

DO i=1, nb_cand
READ (UNIT=10, FMT=’(A22,I10)’) nom_cand(i), nb_voix(i)
END DO
CLOSE(UNIT=10) ! Fermeture fichier
END SUBROUTINE lecture_fichier
END MODULE mod_election

PROGRAM election
USE mod_election
IMPLICIT NONE
CHARACTER(LEN=22), DIMENSION(:), ALLOCATABLE :: nom_cand
INTEGER, DIMENSION(:), ALLOCATABLE :: nb_voix

CALL lecture_fichier("election_pres.dat", nom_cand, nb_voix)


CALL tri_candidats(nom_cand, nb_voix)
CALL affichage_resultats(nom_cand, nb_voix)
END PROGRAM election

Expliquer comment le sous-programme lecture_fichier fonctionne.

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 4/9

Solution :
Le sous-programme lecture_fichier prend en entrée l’argument nom_fichier, qui contient le nom
d’un fichier qu’il ouvre. En cas d’échec, le programme s’arrête avec un message d’erreur. Le sous-programme
lit ensuite nb_cand le nombre de candidats placé dans le premier enregistrement. Ceci lui permet de faire l’al-
location des tableaux dynamiques nom_cand et nb_voix, avec arrêt et message d’erreur éventuels. Ensuite,
à l’aide d’une boucle, le nom et le nombre de voix de chaque candidat sont lus et placés dans les tableaux, puis
le fichier est fermé.

2. On rappelle l’algorithme du tri à bulles, qui trie les n éléments d’un tableau tab de la plus petite valeur à la plus
grande.

Algorithme 1 Tri à bulles du tableau tab. Les variables i et j sont entières, fini est booléenne.
1: Pour j de 1 à n
2: fini ←− vrai
3: Pour i de n − 1 à j par pas de −1
4: Si tab(i + 1) < tab(i) alors
5: Échanger tab(i + 1) et tab(i)
6: fini ←− faux
7: Fin si
8: Fin pour
9: Si fini alors exit
10: Fin pour

Écrire la subroutine de tri, appelée par le programme principal (voir listing plus haut), qui trie le tableau nb_voix
du plus grand nombre de voix au plus petit. Bien entendu, les opérations faites sur le tableau nb_voix devront
également être effectuées sur le tableau nom_cand afin de pas perdre la correspondance entre nombre de voix et
nom des candidats !
La subroutine aura l’interface suivante :
SUBROUTINE tri_candidats(nom_cand, nb_voix)
CHARACTER(LEN=*), DIMENSION(:), INTENT( ??? ) :: nom_cand
INTEGER, DIMENSION(:), INTENT( ??? ) :: nb_voix
END SUBROUTINE tri_candidats

Solution :
SUBROUTINE tri_candidats(nom_cand, nb_voix)
CHARACTER(LEN=*), DIMENSION(:), INTENT(INOUT) :: nom_cand
INTEGER, DIMENSION(:), INTENT(INOUT) :: nb_voix

INTEGER :: i, j, tmp
CHARACTER(LEN=22) :: ctmp
LOGICAL :: fini

DO j = 1, SIZE(nb_voix, 1)
fini = .TRUE.
DO i = SIZE(nb_voix, 1) - 1, j, -1
IF (nb_voix(i+1) > nb_voix(i)) THEN
tmp = nb_voix(i) ; nb_voix(i) = nb_voix(i+1) ; nb_voix(i+1) = tmp
ctmp = nom_cand(i) ; nom_cand(i) = nom_cand(i+1) ; nom_cand(i+1) = ctmp
fini = .FALSE.
END IF
END DO

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 5/9

IF (fini) EXIT
END DO
END SUBROUTINE tri_candidats

3. Écrire la subroutine d’affichage appelée par le programme principal (voir listing plus haut). Cette procédure affichera,
en colonnes parfaitement alignées, le classement, le nom du candidat, et le pourcentage de voix obtenues avec deux
chiffres après le séparateur décimal. On donne ici un extrait de l’affichage attendu à l’écran :
01 - MACRON Emmanuel 24.01 %
...
09 - ASSELINEAU Francois 0.92 %
10 - ARTHAUD Nathalie 0.64 %
11 - CHEMINADE Jacques 0.18 %

Solution :
SUBROUTINE affichage_resultats(nom_cand, nb_voix)
CHARACTER(LEN=*), DIMENSION(:), INTENT(IN) :: nom_cand
INTEGER, DIMENSION(:), INTENT(IN) :: nb_voix

REAL :: pourcentage
INTEGER :: i

DO i = 1, SIZE(nb_voix, 1)
pourcentage = 100.*nb_voix(i)/SUM(nb_voix)
WRITE(*,FMT=’(I2.2,A3,A22,F6.2,A)’) i, ’ - ’, nom_cand(i), pourcentage, " %"
END DO
END SUBROUTINE affichage_resultats

4. Pensez-vous que ce stockage des données sous la forme de deux tableaux soit bien adapté ? Justifier.

Solution :
Non, il aurait été préférable de créer un type dérivé candidat avec des champs nom_cand, nb_voix, etc.
Cela aurait évité de manipuler indépendamment les différents tableaux lors du tri.

Exercice 3 – Le boulier japonais (∼ 1 heure)

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 6/9

Un boulier japonais est constitué d’un certain nombre de


fils (représentés verticaux sur la figure 1), représentant 5 6 0 3
de la droite vers la gauche les unités, dizaines, centaines,
etc... Chaque fil est divisé en deux parties séparées par
une barre centrale : la partie haute contient une boule mo-
bile, et la partie basse quatre. Seules prennent une valeur
les boules activées, c’est-à-dire celles que l’on a amenées
et plaquées contre la barre centrale. Quand elles sont ac-
tivées, la boule du haut prend la valeur 5 et les boules du
bas prennent chacune la valeur 1. Ainsi, pour représenter
le nombre 5603 (cas de la figure 1), il faut inscrire 5 sur
le fil des milliers, ce qui se traduit par la seule activation fil 3 fil 2 fil 1 fil 0
de la boule du haut. Pour les centaines, soit 6, il faut acti-
F IG . 1 – Boulier japonais à 4 fils, représentant le nombre 5603.
ver la boule du haut (5) et une boule du bas (1). Pour les
Les boules activées ont été représentées en foncé, même si, en
dizaines nous avons 0, donc aucune boule n’est activée.
réalité, toutes les boules ont la même couleur.
Pour les unités, 3, trois boules du bas sont activées.
Le nombre de fils du boulier est contenu dans la variable nf, une constante entière égale à 4.

Afin de représenter le boulier, nous définissons le type dérivé boulier qui comprend :
— un champ entier valeur, destiné à prendre la valeur totale représentée par le boulier
— deux champs boul_sup, et boul_inf, qui sont des tableaux entiers dont l’indice est le numéro de fil (de 0
à nf-1). Le tableau boul_sup contiendra, pour chaque fil du boulier pris de droite à gauche, le nombre de
boules activées dans la partie haute (0 ou 1). Le tableau boul_inf contiendra, pour chaque fil du boulier, le
nombre de boules activées dans la partie basse (0, 1, 2, 3 ou 4).

indice (numéro de fil) 0 1 2 3


Le nombre 5603 sera donc stocké de la façon suivante : boul_sup 0 0 1 1
boul_inf 3 0 1 0
1. Dans un module mod_boulier, donner les instructions de déclaration de nf et du type dérivé boulier.

Solution :
MODULE mod_boulier
IMPLICIT NONE
INTEGER, PARAMETER :: nf = 4

TYPE boulier
INTEGER, DIMENSION(0:nf-1) :: boul_sup
INTEGER, DIMENSION(0:nf-1) :: boul_inf
INTEGER :: valeur
END TYPE boulier
END MODULE mod_boulier

Pour les questions 2 à 7, les différentes procédures sont supposées placées dans le module précédent.
2. Écrire une fonction nbmax(n_fils) qui calcule et retourne la plus grande valeur qu’il est possible d’inscrire sur
un boulier à n_fils fils. On notera qu’un entier e inscrit sur le fil i donne une contribution e × 10i à la valeur
représentée par le boulier.

Solution :

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 7/9

INTEGER FUNCTION nbmax(n_fils)


INTEGER, INTENT(IN) :: n_fils
INTEGER :: i

nbmax = 0
DO i = 0, n_fils-1
nbmax = nbmax + 9*10**i
ENDDO
! ou bien tout simplement
! nbmax = 10**n_fils - 1
END FUNCTION nbmax

3. Écrire la procédure afficherBoulier(b) qui affiche sur deux lignes le nombre de boules activées dans la partie
haute, et le nombre de boules activées dans la partie basse de la variable b de type dérivé boulier (attention à
l’ordre : les unités doivent être à droite). On suppose ici que les champs de la variable b ont déjà été initialisés, de
sorte qu’il suffit de les afficher.
On utilisera un format. Pour l’exemple donné plus haut, l’affichage devra donner :
haut : 1 1 0 0
bas : 0 1 0 3

Solution :
SUBROUTINE afficherBoulier(b)
TYPE(boulier), INTENT(IN) :: b

PRINT ’("haut :",1000I2)’, b%boul_sup(nf-1:0:-1)


PRINT ’("bas :",1000I2)’, b%boul_inf(nf-1:0:-1)
END SUBROUTINE afficherBoulier

4. Pour initialiser un boulier b, il faut activer des boules sur chaque fil. Écrire le sous-programme activerBoules
(b, ifil, e) qui permet l’activation des boules sur le fil ifil du boulier b, de manière à représenter l’entier
e sur ce fil. L’entier e est connu lors de l’appel au sous-programme. Il est compris au sens large entre 0 et 9 (il n’est
pas nécessaire de contrôler la valeur de e).

Solution :
SUBROUTINE activerBoules(b, ifil, e)
TYPE(boulier), INTENT(INOUT) :: b
INTEGER, INTENT(IN) :: ifil, e

IF (e < 5) THEN
b%boul_sup(ifil) = 0
b%boul_inf(ifil) = e
ELSE
b%boul_sup(ifil) = 1
b%boul_inf(ifil) = e - 5
ENDIF
END SUBROUTINE activerBoules

5. Expliquer ce que fait la procédure X suivante. Illustrer avec nf = 4 et n = 183, et indiquer le contenu de T qui
serait affiché à la fin de la procédure.

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 8/9

SUBROUTINE X(n, T)
INTEGER, INTENT(IN) :: n
INTEGER, DIMENSION(0:nf-1), INTENT(OUT) :: T
INTEGER :: i, nb

nb = n
DO i = 0, nf-1
T(i) = MOD(nb,10)
nb = nb/10
ENDDO
PRINT *, "T = ", T
END SUBROUTINE X

Solution :
La procédure prend en entrée un entier n et le décompose en unités, dizaines, etc... dans le tableau de sortie T .
Par exemple, si n = 183, alors initialement nb = 183, et MOD(183, 10) vaut 3 qui est affecté dans T (0). Puis
nb = 183/10 prend la valeur 18, et MOD(18, 10) vaut 8, affecté dans T (1). Puis nb = 18/10 prend la valeur 1,
et MOD(1, 10) vaut 1, affecté dans T (2). Puis nb = 1/10 prend la valeur 0, et MOD(0, 10) vaut 0, affecté dans
T (3). L’affichage de T donne donc T = 3 8 1 0.

6. A l’aide des procédures nbmax, X et activerBoules, écrire le sous-programme initBoulier(b) qui effec-
tue les tâches suivantes :
— demande à l’utilisateur de saisir un nombre n, la saisie de n étant recommencée tant que ce nombre est négatif
ou nul, ou est trop grand pour le boulier,
— appelle le sous-programme X et active correctement les boules sur chaque fil du boulier b.
On pourra avoir besoin d’un tableau dynamique T(0:nf-1), à allouer et initialiser à 0 en début de sous-programme.

Solution :
SUBROUTINE initBoulier(b)
TYPE(boulier), INTENT(INOUT) :: b
INTEGER n, i, ok
INTEGER, DIMENSION(:), ALLOCATABLE :: T

ALLOCATE(T(0:nf-1),stat=ok)
IF (ok /= 0) STOP "erreur allocation T"
T(:) = 0

PRINT *, "Entrer un nombre 0 < n <= ", nbmax(nf)


READ *, n
DO WHILE (n > nbmax(nf) .OR. n <=0)
PRINT *, "Entree non valide, recommencez !"
READ *, n
END DO

! decomposition de n en puissances de 10
CALL X(n,T)

DO i = 0, nf-1
CALL activerBoules(b, i, T(i))
ENDDO

END SUBROUTINE initBoulier

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017
UE 2A005 Version enseignant Examen 2016-2017 – page 9/9

7. Écrire le sous-programme valeurBoulier(b) qui, à l’aide des champs boul_sup et boul_inf du boulier b
donné en entrée, calcule la valeur représentée et l’affecte au champ valeur du boulier b.

Solution :
SUBROUTINE valeurBoulier(b)
TYPE(boulier), INTENT(INOUT) :: b
INTEGER :: i, n

b%valeur = 0
DO i = 0, nf-1
b%valeur = b%valeur + (5*b%boul_sup(i) + b%boul_inf(i)) * 10**i
ENDDO
END SUBROUTINE valeurBoulier

8. Écrire un programme principal boulier_japonais qui utilise le module mod_boulier contenant toutes les
déclarations et procédures. Le programme déclare une variable BJ de type dérivé boulier, initialise ce boulier,
l’affiche, calcule ensuite la valeur représentée par le boulier et l’affiche (ce qui permet de vérifier que l’initialisation
s’est bien passée).

Solution :
PROGRAM boulier_japonais
USE mod_boulier
IMPLICIT NONE
TYPE(boulier) :: BJ

CALL initBoulier(BJ)
CALL afficherBoulier(BJ)
CALL valeurBoulier(BJ)
PRINT *, "valeur boulier = ", BJ%valeur
END PROGRAM boulier_japonais

2016-2017(by
c UPMC/Licence Mécanique/2A005) 9 mai 2017

Vous aimerez peut-être aussi