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, à :
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #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); }
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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
... 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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#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]); } |