Exercice 1
Si (j, m, a) n’est pas le dernier jour d’un mois alors son lendemain est (j+1, m, a), sinon c’est (1, m+1, a) sauf si m = 12, auquel cas le lendemain est (1, 1, a+1). Nous devons donc écrire la condition qui caractérise que (j,m, a) est le dernier jour d’un mois, ce qui équivaut, puisque la date est garantie correcte, à :
- j = 31, ou bien
- j = 30 et le mois est avril, juin, septembre ou novembre, ou bien
- j = 29 et le mois est février, ou bien
- j = 28, le mois est février et l’année n’est pas bissextile.
D’autre part, une année est bissextile si elle est divisible par 4 mais pas par 100. Cependant, les années multiples de 400 sont bissextiles. D’où le programme suivant, dans lequel on reconnaît sans peine la traduction des quatre cas ci-dessus.
#include #include int j, m, a, i; main() { printf("j m a ?\n"); scanf("%d%d%d", &j, &m, &a); if (j == 31 || (j == 30 && (m == 4 || m == 6 || m == 9 || m == 11)) || (j == 29 && m == 2) || (j == 28 && m == 2 && ! (a % 4 == 0 && a % 100 != 0 || a % 400 == 0))) { j = 1; if (m == 12) { m = 1; a = a + 1; } else m = m + 1; } else j = j + 1; printf("%d %d %d\n", j, m, a); }
Exercice 2
Tout le travail à faire ici c’est programmer la formule donnée (nous l’acceptons sans explication!) sans y faire le moindre regroupement ou simplification car les barres de fraction indiquent des quotients entiers, donc impliquent des troncations qui sont nécessaires à la formule (par exemple, à cause de ces troncations, -2ns+ns/4 n’est pas toujours égal à -7ns/4).
Voici le programme, pour une fois il n’y a pas tellement de possibilités :
#include #include int j, m, a, as, ns, f; main() { printf("j m a ? "); scanf("%d%d%d", &j, &m, &a); printf("le %d/%02d/%d est un ", j, m, a); if (m >= 3) m = m - 2; else { m = m + 10; a = a - 1; } ns = a / 100; as = a % 100; f = (j + as + as / 4 - 2 * ns + ns / 4 + (26 * m - 2) / 10) % 7; if (f < 0) f = f + 7; switch (f) { case 0: printf("dimanche\n"); break; case 1: printf("lundi\n"); break; case 2: printf("mardi\n"); break; case 3: printf("mercredi\n"); break; case 4: printf("jeudi\n"); break; case 5: printf("vendredi\n"); break; default: printf("samedi\n"); } }
Après avoir décalé le mois et l’année comme indiqué (puisque m, a et m1, a1 ne coexistent pas, il n’y a pas besoin de deux paires de variables distinctes), on sépare le numéro de l’année en deux morceaux : a = 2003 donnens = 20 et as = 3 puis on calcule f.
Dans de nombreux cas f est négatif. Par exemple, pour le 1er mars 2002, f = -30. Cela pose un problème car là où un arithméticien dirait que -30 % 7 vaut 5 (en effet, -30 = -5 x 7 + 5) la bibliothèque C dira que -30 % 7 vaut -2 (car -30 = -4 x 7 – 2). Il se trouve que 5 et -2 sont deux réponses justes mais -2 nous gêne pour la suite du programme, d’où l’ajustement opéré [la bibliothèque garantit que x % n est compris, quel que soit x, entre – (n – 1) et (n – 1)].
Enfin, il n’y a plus qu’à traduire le résultat obtenu, un nombre compris entre 0 et 6, et un texte « lundi », « mardi », etc. La solution proposée est la plus simple. Une solution au mieux équivalente, au pire un poil moins efficace, consiste à remplacer switch par une cascade de if :
... if (f == 0) printf("dimanche\n"); else if (f == 1) printf("lundi\n"); else if (f == 2) printf("mardi\n"); else if (f == 3) printf("mercredi\n"); else if (f == 4) printf("jeudi\n"); else if (f == 5) printf("vendredi\n"); else printf("samedi\n"); }
Si vous connaissez les tableaux de chaînes de caractères (c’est assez pointu, on y reviendra plus tard) voici une solution plus élégante :
#include #include int j, m, a, ns, f; char *jour[] = { "dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi" }; main() { printf("j m a ? "); scanf("%d%d%d", &j, &m, &a); printf("le %d/%02d/%d est un ", j, m, a); if (m >= 3) m = m - 2; else { m = m + 10; a -= 1; } ns = a / 100; a = a % 100; f = (j + a + a / 4 - 2 * ns + ns / 4 + (26 * m - 2) / 10) % 7; if (f < 0) f = f + 7; printf("%s\n", jour[f]); }