Période: été 2011 Sujet: Boucles, manipulation de chaînes de caractères
zRom
L'exercice de ce mois nous fera voyager dans un autre pays assez connu qui est : l'Italie !
Non, non, je ne vous offre pas un voyage tous frais payés, nous allons utiliser les chiffres romains !
Les chiffres romains
Vous connaissez sûrement les chiffres romains, ils sont utilisés un peu partout, pour les siècles (XXè siècle), le nom de rois (Louis XVI, Henri IV), les montres, les chapitres de documents, les numéros de page, etc. .
Mais la question est : savez-vous compter en nombre romain et savez-vous comment ça fonctionne ?
L'exercice du moment nous aidera justement à faire la conversion chiffres arabes (notre système de compter 0,1,2,etc.) et les chiffres romains (ainsi que l'inverse).
Quelques explications s'imposent.
Tout d'abord, on va présenter les nombres (qui sont en fait des lettres) et nombres arabes :
Arabes
Romains
0
Inexistant
1
I
5
V
10
X
50
L
100
C
500
D
1000
M
Pour compter, c'est très simple, il suffit de lire le nombre de droite à gauche (vous pouvez aussi le faire de gauche à droite, seulement c'est plus simple de droite à gauche ) et d'additionner tous les nombres. A une exception près, si le nombre qui précède le nombre 'courant' est inférieur à celui-ci, on le soustrait. Fastoche, non ?
On va se fixer une règle : on ne peut soustraire qu'un nombre au nombre juste en dessous. Donc, on ne soustrait I qu'à V ou X, X qu'à L ou C, C qu'à D ou M (j'ai zappé ceux qui étaient inutiles).
Les soustractions sont assez rare si vous remarquez bien, on notera le 4 et le 9, le reste... pas grand chose à voir.
Leur système de comptage ne permet d'écrire que des nombres jusqu'à 4999. Dans nos exercices, on se limitera à 3999.
Un peu de comptage :
2 s'écrit II
3 s'écrit III
4 peut s'écrire IIII ou IV (I précède V, donc on soustrait 1 à 5 -> 4)
29 peut s'écrire XXVIIII (10+10+5+1+1+1+1) ou XXIX (10+10+(10-1))
90 s'écrit XC (100-10)
Je pense que vous aurez compris, rien de bien compliqué !
Exercice 1
Vous devez écrire un programme qui prend un nombre romain dans sa forme correcte et la plus courte (l'utilisateur est intelligent) et donne le résultat en nombre arabe.
Exercice 2
Vous devez écrire un programme qui prend un nombre arabe et le convertit en nombre romain dans sa forme la plus courte.
Exercice 3
Vous devez écrire un programme qui prend un nombre romain quelconque et écrit sa forme arabe ainsi que sa forme romaine la plus courte.
29 peut s'écrire XXVIII (10+10+V+1+1+1+1) ou XXIX (10+10+(10-1))
Une petite faute : tu as oublié un I (29 peut s'écrire XXVIIII) et tu as écrit (10+10+V+1+1+1+1) au lieu de (10+10+5+1+1+1+1)
Par contre, es-tu certain que 4 puisse s'écrire IIII ?
En fait, c'est du vieux romain. Dans le vieux romain, on pouvait écrire 4 IIII mais il y a eu une révision du langage et donc on s'est mis à écrire 4 IV.
@ben83510 :
Ce n'est pas vraiment l'endroit pour poster une question, créer plutôt un autre topic. Par-contre, tu confonds 'i' et 'j' à partir de if(chiffre[i]==nbRomain[j]) tu dois utiliser 'j'.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles- ♡ Copying is an act of love.
* Tu pourrais faire une vérifications pour les nombres supérieures à 3999 ? Pour pas afficher les symbole bazars.
* Un peu lourd 256 cases pour seulement 7 cases utiles, non ?
* Tu pourrais géré les nombres entrer en minuscules ?
Merci pour tes remarques.
*Oui, pourquoi pas, au cas ou il entrerait un nombre entre 4000 et 4999...
*256 ce n'est pas lourd du tout, c'est même très petit. Par contre si tu trouve un moyen aussi simple pour gérer ce tableau, qui n'utilise que 7 cases, moi je dis pas non (mais ça m'étonnerait)
*Oui ça ne couterait rien en effet
Avec tes 2 améliorations :
#include <stdio.h>
#include <string.h>
int romainVersArabe(char *str)
{
int vals[256] = {0};
int i, res=0;
vals['I'] = vals['i'] = 1;
vals['V'] = vals['v'] = 5;
vals['X'] = vals['x'] = 10;
vals['L'] = vals['l'] = 50;
vals['C'] = vals['c'] = 100;
vals['D'] = vals['d'] = 500;
vals['M'] = vals['m'] = 1000;
for(i=0; str[i]; i++)
{
if(vals[(int)str[i+1]] > vals[(int)str[i]])
res -= vals[(int)str[i]];
else
res += vals[(int)str[i]];
}
return res;
}
char *arabeVersRomain(int N, char *str)
{
const char *p10[] = {"I", "X", "C", "M"}, *p5[] = {"V","L","D"};
int size, i;
str[0] = 0;
for(i=0; N > 0; i++)
{
if(N%5 == 4)
{
if(N%10 == 4)
strcat(str, p5[i]);
if(N%10 == 9)
strcat(str, p10[i+1]);
strcat(str, p10[i]);
}
else
{
int j=0;
for(j=0; j<N%5; j++)
strcat(str, p10[i]);
if(N%10 >= 5)
strcat(str, p5[i]);
}
N /= 10;
}
size = strlen(str); /*On retourne la chaine*/
for(i=0; i<size/2; i++)
{
int temp = str[i];
str[i] = str[size-i-1];
str[size-i-1] = temp;
}
return str;
}
int main(void)
{
char romain[100] = "";
int resultat;
printf("Entrez un nombre en chiffre romains (compris entre 1 et 3999) :\n");
scanf("%s", romain);
resultat = romainVersArabe(romain);
if(resultat > 3999)
printf("Vous avez ecris n'importe quoi\n");
printf("Valeur en chiffres arabes : %d\n", resultat);
printf("Ecriture correcte en chiffres romains : %s\n", arabeVersRomain(resultat, romain));
return (0);
}
2 tableaux dont l'indice permettrait de faire correspondre les valeurs. Par exemple.
Je ne vois pas ou tu veux en venir. Peux-tu montrer un exemple?
Par contre j'ai une question (problème que j'ai rencontré en codant mon code), pourquoi le compilateur n'est pas content lorsque j'utilise un char pour l'indice de mon tableau. Par exemple, ici (j'ai dû faire un cast) :
Par contre j'ai une question (problème que j'ai rencontré en codant mon code), pourquoi le compilateur n'est pas content lorsque j'utilise un char pour l'indice de mon tableau. Par exemple, ici (j'ai dû faire un cast) :
Parce que le type char peut être signé ou non signé suivant la machine. Cela peut réserver des surprises
Sinon, voici mon code pour le premier exercice (conversion Romains -> Arabes):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char const *Nombres[] = { "IV", "IX", "XL", "XC", "CD", "CM", "I", "V",
"X" , "L" , "C" , "D" , "M" };
static long const Valeurs[] = { 4 , 9 , 40 , 90 , 400 , 900 , 1 , 5 ,
10 , 50 , 100 , 500 , 1000 };
long
rtoa (char const *s)
{
long n = 0;
while (*s) {
unsigned i;
for (i = 0; i < sizeof Nombres; i++) {
if (strncmp (s, Nombres[i], strlen (Nombres[i])) == 0) {
n += Valeurs[i];
s += strlen (Nombres[i]);
break;
}
}
}
return n;
}
int
main (void)
{
char buffer[32];
if (scanf ("%31s", buffer)) {
long n;
n = rtoa (buffer);
printf ("%ld\n", n);
}
return EXIT_SUCCESS;
}
Je pense que vous aurez compris, rien de bien compliqué !
Hum, je trouve pas que ce soit si facile ...
Citation : Pouet_forever
un nombre romain dans sa forme correcte et la plus courte (l'utilisateur est intelligent) et donne le résultat en nombre arabe.
nombre romain ... nombre arabe, ça fait bizarre comme formulation, je pense que tu pourrais dire nombre en chiffres arabes, nombre en chiffres romains.
Citation : Pouet_forever
zRom
zRom ? titre curieux, j'ai pensé à une ROM (read only memory) embarquée, je dois être un peu obsédé Je sais pas sinon: zÉsar, zRome, zRomains, etc.
Citation : Pouet_forever
Exercice 1
Vous devez écrire un programme qui prend un nombre romain dans sa forme correcte et la plus courte (l'utilisateur est intelligent) et donne le résultat en nombre arabe.
Exercice 2
Vous devez écrire un programme qui prend un nombre arabe et le convertit en nombre romain dans sa forme la plus courte.
Exercice 3
Vous devez écrire un programme qui prend un nombre romain quelconque et écrit sa forme arabe ainsi que sa forme romaine la plus courte.
Plus court, plus long je vois pas trop l'intérêt, pour moi il n'y a qu'un forme d'écriture.
J'avais écrit des codes il y a deux ou trois ans, je les ressors pour ainsi dire tels quels :
#include <stdio.h>
#include <string.h>
void decimal_vers_romain(char *romain, int x)
{
#define MILLIERS 4
char *dix = "IXCM";
char *cinq = "VLD";
int position_decimal = 0, position_romain = 0;
int i, nb_chiffres;
char decimal[5];
nb_chiffres = sprintf(decimal, "%d", x);
for (i = 0; i < nb_chiffres; i++)
decimal[i] -= '0';
for (; position_decimal < nb_chiffres; position_decimal++)
{
char chiffre = decimal[position_decimal];
int type_chiffre = nb_chiffres - position_decimal - 1;
if (type_chiffre == MILLIERS)
for (i = 0; i < chiffre; i++)
romain[position_romain++] = 'M';
else
switch (chiffre)
{
case 1:
case 2:
case 3:
for (i = 0; i < chiffre; i++)
romain[position_romain++] = dix[type_chiffre];
break;
case 4:
romain[position_romain++] = dix[type_chiffre];
romain[position_romain++] = cinq[type_chiffre];
break;
case 5:
romain[position_romain++] = cinq[type_chiffre];
break;
case 6:
case 7:
case 8:
romain[position_romain++] = cinq[type_chiffre];
for (i = 0; i < chiffre - 5; i++)
romain[position_romain++] = dix[type_chiffre];
break;
case 9:
romain[position_romain++] = dix[type_chiffre];
romain[position_romain++] = dix[type_chiffre + 1];
break;
}
}
}
int romain_vers_decimal(char *romain)
{
char chiffresRomains[] = "IVXLCDM";
int valeursDecimales[sizeof(chiffresRomains) - 1] =
{ 1, 5, 10, 50, 100, 500, 1000 };
int nb_chiffres = strlen(romain), i, ancien, nouveau;
int resultat;
ancien = strchr(chiffresRomains, romain[nb_chiffres - 1]) - chiffresRomains;
resultat = valeursDecimales[ancien];
for (i = nb_chiffres - 2; i >= 0; i--)
{
nouveau = strchr(chiffresRomains, romain[i]) - chiffresRomains;
if (nouveau >= ancien)
resultat += valeursDecimales[nouveau];
else
resultat -= valeursDecimales[nouveau];
ancien = nouveau;
}
return resultat;
}
int main(void)
{
int i;
char romain[100] = { 0 };
/* exemple inspirés par
http://en.wikipedia.org/wiki/Roman_numerals#Modern_Roman_numerals */
char *romains[] =
{ "DCLXVI", "MDCLXVI", "MCCCCCCVI", "MMMDCCCLXXXVIII", "MMMCMXCIX" };
for (i = 0; i < (int) (sizeof romains / sizeof *romains); i++)
printf("%s = %d\n", romains[i], romain_vers_decimal(romains[i]));
decimal_vers_romain(romain, 2011);
printf("%s = %d\n", romain, 2011);
/* Test complet de 1 à 3999 */
for (i = 1; i < 4000; i++)
{
char romain[100] = { 0 };
decimal_vers_romain(romain, i);
if (romain_vers_decimal(romain) != i)
{
printf("%d %s : calcul faux\n", i, romain);
return 0;
}
}
printf("Test 1 -> 3999 : OK\n");
return 0;
}
Parce que le type char peut être signé ou non signé suivant la machine. Cela peut réserver des surprises
Oui mais je vois pas en quoi c'est un problème (tu peux très bien avoir des indices négatifs dans un tableau). En tous cas chez moi, aucun avertissement.
Citation : @che
int value[] = {1000, 500, 100, 50, 10, 5, 1}; /* Les nombres correspondants aux chiffre romain */
char *digit = "MDCLXVI"; /* Les chiffres romains par ordre décroissant */
La position permet de passer de l'un a l'autre.
Oui mais c'est quand même très lourd un truc comme ça, un des défauts du C de ne pas avoir nativement des tableaux associatifs, je suppose qu'en C++ on n'a pas ce genre de lacune.
int value[] = {1000, 500, 100, 50, 10, 5, 1}; /* Les nombres correspondants aux chiffre romain */
char *digit = "MDCLXVI"; /* Les chiffres romains par ordre décroissant */
La position permet de passer de l'un a l'autre.
Oui mais c'est quand même très lourd un truc comme ça, un des défauts du C de ne pas avoir nativement des tableaux associatifs, je suppose qu'en C++ on n'a pas ce genre de lacune.
Pas plus qu'utiliser 256 cases
Au pire en un tableau on peut faire : intvalue[]={'M','D','C','L','X','V','I',1000,500,100,50,10,5,1};
Ou il suffit d'ajouter 7 pour avoir la valeur.
Oui mais je vois pas en quoi c'est un problème (tu peux très bien avoir des indices négatifs dans un tableau).
D'accord, mais c'est assez rare de voir des indices négatifs dans les tableaux, en général ça sent l'erreur, surtout si ce nombre négatif est obtenu suite au dépassement de la valeur maximale d'un type.
Maintenant, à bien y réfléchir, l'avertissement est sans doute plutôt dû à la taille variable d'un char (un byte, soit 8, 9, 15 (ou plus) octets bits ).
Wow chapeau, l'implémentation de ton algo est vraiment astucieuse je trouve, en tout cas je n'en avais jamais vu une aussi simple...
Merci m'sieur !
Moi j'aime bien ta fonction "romainVersArabe" qui à l'air super rapide (je ne l'ai pas testée en vrai, seulement de tête), surtout qu'elle gère le 0 de fin de chaîne sans cas particulier !
A froid, je ne vois pas non plus comment réduire le tableau de 256 cases sans faire au moins une passe sur la chaîne.
@ candide et @che :
Bon, apparement "atoi" n'a pas l'air de vous plaire.
On peut utiliser "snprintf" à la place, ça doit être plus portable (du moins ça fonctionne sur Windows et Linux). Ca vous irait ?
@ candide et @che :
Bon, apparement "atoi" n'a pas l'air de vous plaire.
On peut utiliser "snprintf" à la place, ça doit être plus portable (du moins ça fonctionne sur Windows et Linux). Ca vous irait ?
Je vois pas trop pourquoi tu t'amuses à manipuler ton nombre à convertir sous forme d'une chaîne de caractères, avec un peu d'arithmétique élémentaire tu as le même résultat.
Jette un oeil à mon fonction zrom_set_value() pour voir de quoi je parle.
L'idéal ce serait de faire quelques tests et de voir les temps
Je vois pas trop pourquoi tu t'amuses à manipuler ton nombre à convertir sous forme d'une chaîne de caractères, avec un peu d'arithmétique élémentaire tu as le même résultat.
Jette un oeil à mon fonction zrom_set_value() pour voir de quoi je parle.
Je préviens tout de suite que je ne veux pas lancer un débat !
Pour répondre à ta question, je passe par ce subterfuge très spécifiquement pour ne pas avoir à écrire 4 lignes quasi-identiques comme tu l'as fait. Ca me permet aussi de ne faire que le nombre d'itérations nécessaire. (En plus ça m'évite aussi les modulos).
Je préviens tout de suite que je ne veux pas lancer un débat !
Pour répondre à ta question, je passe par ce subterfuge très spécifiquement pour ne pas avoir à écrire 4 lignes quasi-identiques comme tu l'as fait. Ca me permet aussi de ne faire que le nombre d'itérations nécessaire. (En plus ça m'évite aussi les modulos).
Ce n'est pas non plus mon intention de lancer un débat
Je comprends mieux, c'est juste que ça me semblait peu naturel. En fait tu délègues juste "les modulos" à itoa(), c'est vrai que finalement ça revient au même.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.