OVH Cloud OVH Cloud

écriture des nombres (formatage de sortie)

32 réponses
Avatar
KooK
Bonjour,

Je voudrais écrire les nombres avec un espace tous les 3 chiffres afin
de les rendre plus lisibles. J'ai regardé du coté de setf et setw sans
succès. Suis-je passé à côté ? Quel fonction utiliser ?

exemple :
int main(void)
{
int a = 1000000;
//fonction pour faire afficher 1 000 000
cout << a << endl;
return 0;
}

Si vous savez répondre à la même question en C je suis preneur aussi.

KooK

10 réponses

1 2 3 4
Avatar
KooK
Il faut utiliser les locales, plus particulièrement le facet numpunct :

class MyNumPunct : public std::numpunct<char>
{
protected:
virtual std::string do_grouping() const
{
return "3"; //groupes de 3 chiffres. Oui, le formattage de cetet
chaine est stupide.....
}

virtual char do_thousands_sep() const
{
return ' '; //séparés par espace
}
};

int main()
{
MyNumPunct* punct=new MyNumPunct(); //will be destroyed by the locale
destructor

//create a new locale based on cout, but using our specific numpunct
std::locale loc(std::cout.getloc (), punct);

std::cout.imbue (loc);
std::cout<<2123456789<<std::endl;
}

cf
http://www.roguewave.com/support/docs/leif/sourcepro/html/stdlibref/num-put.html
pour plus de détails.

Arnaud
MVP - VC




Merci pour cette réponse, je ne connaissais pas le système des locales.
Je suis même surpris de voir que ma question a mené tant de réflexions.

Chez moi ta réponse marche très bien (g++, Debian), mais j'ai pu faire
encore plus simple :
int main(void)
{
double pi_M = 3141.5926;
//pour afficher correctement
cout.setf(ios::fixed);
cout << setprecision(4);
cout << pi_M << endl; //3141.5926
//pour comparer les sorties
printf("printf : %.4fn", pi_M); //3141.5926

cout << "cout.imbue(cout.getloc())n";
//meme resultat que locale::global(locale(""));
cout.imbue(cout.getloc());
cout << pi_M << endl; //3141.5926
printf("printf : %.4fn", pi_M); //3141,5926 -> la virgule

cout << "cout.imbue(locale::locale("fr_FR.UTF-8"))n";
cout.imbue(locale::locale("fr_FR.UTF-8"));
cout << pi_M << endl; //3 141,5926 -> OK
printf("printf : %.4fn", pi_M); //3141,5926 -> pas d'espace

return 0;
}

Voilà en choisissant tout simplement la bonne locale :P , pas sûr que
sous windows ça marche (mais je m'en moque). En C le mécanisme est
analogue d'après ce que j'ai lu.
Par contre j'imagine que si je veux grouper les décimales par trois il
va falloir que je dérive _mais je me sers de moins de 3 décimales pour
le moment.

Encore merci,
KooK

Avatar
Olivier Miakinen

[...]


cout << "cout.imbue(locale::locale("fr_FR.UTF-8"))n";
cout.imbue(locale::locale("fr_FR.UTF-8"));
cout << pi_M << endl; //3 141,5926 -> OK
printf("printf : %.4fn", pi_M); //3141,5926 -> pas d'espace

return 0;
}

Voilà en choisissant tout simplement la bonne locale :P , pas sûr que
sous windows ça marche (mais je m'en moque). En C le mécanisme est
analogue d'après ce que j'ai lu.


Il serait intéressant de voir ce que cela donne pour l'Inde et le
Pakistan (malheureusement je ne connais pas les codes de langue et
de pays).

<cit. http://www.miakinen.net/vrac/nombres#chiffres>
Dans quelques pays (Inde et Pakistan), les chiffres sont séparés
par paires, sauf les 3 premiers (10,00,000 = 1 000 000) [quid].
</>

Par contre j'imagine que si je veux grouper les décimales par trois il
va falloir que je dérive _mais je me sers de moins de 3 décimales pour
le moment.


Dans mes recherches pour ma page sur l'écriture des nombres, je n'ai
rien trouvé à propos d'une éventuelle séparation des décimales. Par
défaut, je supposerais donc qu'il n'y en a pas (et que le comportement
que tu as constaté est donc correct).

--
Olivier Miakinen


Avatar
Olivier Miakinen

Il serait intéressant de voir ce que cela donne pour l'Inde et le
Pakistan (malheureusement je ne connais pas les codes de langue et
de pays).


J'ai trouvé : dans les deux cas c'est en hindi, code "hi" (j'ignore si
le nom du pays est obligatoire).

<cit. http://www.miakinen.net/vrac/nombres#chiffres>
Dans quelques pays (Inde et Pakistan), les chiffres sont séparés
par paires, sauf les 3 premiers (10,00,000 = 1 000 000) [quid].
</>


Confirmation sur <http://joel.toonywood.org/blog/2005-08.html#e.19> :

<cit.>
Petite curiosité au sujet des chiffres, en Inde, ils ne séparent pas par
milliers comme on le fait (milliers, millions, milliards, ...), mais
regroupent d'abord les trois derniers chiffres comme nous, ensuite,
c'est cent mille (1,00,000) aussi appelé lakh, et après dix millions
(1,00,00,000) : crore [...]
</cit.>

Par contre j'imagine que si je veux grouper les décimales par trois il
va falloir que je dérive _mais je me sers de moins de 3 décimales pour
le moment.


Dans mes recherches pour ma page sur l'écriture des nombres, je n'ai
rien trouvé à propos d'une éventuelle séparation des décimales. Par
défaut, je supposerais donc qu'il n'y en a pas (et que le comportement
que tu as constaté est donc correct).


Là, la question reste ouverte.

--
Olivier Miakinen
Troll du plus sage chez les conviviaux : le nouveau venu, avec
son clan, s'infiltre dans les groupes de nouvelles. (3 c.)


Avatar
kanze
Olivier Miakinen wrote:

[...]


cout << "cout.imbue(locale::locale("fr_FR.UTF-8"))n";
cout.imbue(locale::locale("fr_FR.UTF-8"));
cout << pi_M << endl; //3 141,5926 -> OK
printf("printf : %.4fn", pi_M); //3141,5926 -> pas d'espace

return 0;
}

Voilà en choisissant tout simplement la bonne locale :P ,
pas sûr que sous windows ça marche (mais je m'en moque). En
C le mécanisme est analogue d'après ce que j'ai lu.


Il serait intéressant de voir ce que cela donne pour l'Inde et
le Pakistan (malheureusement je ne connais pas les codes de
langue et de pays).

<cit. http://www.miakinen.net/vrac/nombres#chiffres>
Dans quelques pays (Inde et Pakistan), les chiffres sont séparés
par paires, sauf les 3 premiers (10,00,000 = 1 000 000) [quid].
</>


C'est prévu. Il faut simplement que do_grouping renvoie "32"
(et que do_thousands_sep renvoie ',', évidemment). La règle,
c'est que le dernier grouping se répète.

Plus intéressant, c'est le cas de l'arabe, où les chiffres
apparaissent avec le chiffre de poids faible d'abord, à
l'inverse des notres, du point de vue de la direction normale de
l'écriture.

Par contre j'imagine que si je veux grouper les décimales
par trois il va falloir que je dérive _mais je me sers de
moins de 3 décimales pour le moment.


Dans mes recherches pour ma page sur l'écriture des nombres,
je n'ai rien trouvé à propos d'une éventuelle séparation des
décimales. Par défaut, je supposerais donc qu'il n'y en a pas
(et que le comportement que tu as constaté est donc correct).


Je suppose par là qu'il veut dire : les chiffres derrière le
décimal. En effet, la norme ne prévoit rien. Dans la pratique,
je crois que c'est assez arbitraire ; ça ne m'étonnerait pas,
par exemple, de voir une table de logrithmes où les chiffres
sont régroupés par cinq. D'après mes souvenirs, Plauger a dit
une fois que son implémentation (donc, celle de VC++) a une
extension pour le supporter, mais je n'en sais pas plus (et
l'extension n'est peut-être présente que dans les versions
étendues de la bibliothèque qu'il vend directement).

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Olivier Miakinen

Il serait intéressant de voir ce que cela donne pour l'Inde et
le Pakistan (malheureusement je ne connais pas les codes de
langue et de pays).

<cit. http://www.miakinen.net/vrac/nombres#chiffres>
Dans quelques pays (Inde et Pakistan), les chiffres sont séparés
par paires, sauf les 3 premiers (10,00,000 = 1 000 000) [quid].
</>


C'est prévu. Il faut simplement que do_grouping renvoie "32"
(et que do_thousands_sep renvoie ',', évidemment). La règle,
c'est que le dernier grouping se répète.


C'est une bonne nouvelle.

Plus intéressant, c'est le cas de l'arabe, où les chiffres
apparaissent avec le chiffre de poids faible d'abord, à
l'inverse des notres, du point de vue de la direction normale de
l'écriture.


Je ne savais pas comment c'était traité en C et C++, mais dans les
pages HTML avec Unicode, c'est juste un peu plus compliqué que ça :
les chiffres apparaissent bien dans le même « ordre » que pour nous
(chiffre de poids fort en premier), mais c'est la direction d'écriture
qui change en cours de route (de right-to-left pour les lettres, elle
passe temporairement à left-to-right pour les nombres).

Si la même convention existait en français, le texte « Voilà 542 euros »
s'écrirait ainsi :

V
oV
ioV
lioV
àlioV
àlioV
5 àlioV
54 àlioV
542 àlioV
542 àlioV
e 542 àlioV
ue 542 àlioV
rue 542 àlioV
orue 542 àlioV
sorue 542 àlioV

Dans mes recherches pour ma page sur l'écriture des nombres,
je n'ai rien trouvé à propos d'une éventuelle séparation des
décimales. Par défaut, je supposerais donc qu'il n'y en a pas
(et que le comportement que tu as constaté est donc correct).


Je suppose par là qu'il veut dire : les chiffres derrière le
décimal.


Oui, exactement. En français on dirait « les chiffres après la
virgule », ou « les chiffres après le point décimal » si on parle
d'un texte anglais. Mais on les appelle aussi tout simplement les
« décimales ».

<cit. http://atilf.atilf.fr/>
DÉCIMALE
II. Substantif
A. Subst. fém.
1. MATH. Chiffre placé à droite de la virgule dans un nombre décimal.
</cit.>

En effet, la norme ne prévoit rien. Dans la pratique,
je crois que c'est assez arbitraire ; ça ne m'étonnerait pas,
par exemple, de voir une table de logrithmes où les chiffres
sont régroupés par cinq.


Oui, je reconnais que tu as raison : j'en ai déjà vu.

D'après mes souvenirs, Plauger a dit
une fois que son implémentation (donc, celle de VC++) a une
extension pour le supporter, mais je n'en sais pas plus (et
l'extension n'est peut-être présente que dans les versions
étendues de la bibliothèque qu'il vend directement).


Ok.

--
Olivier Miakinen


Avatar
Sylvain
Arnaud Debaene wrote on 06/07/2006 08:13:

Ah? J'ai pourtant testé mon exemple avec Visual 2005 sans problèmes ;-)


j'ai indiqué "Platform SDK" (package bin/inc/lib) pas clean-install de
vs2005, ça fait surement une diff sur le contenu.

et tu l'as testé avec les include idoines, comme mon vocabulaire de base
se limite à stdio.h et string.h, ça ne pouvoit pas compiler tout seul -
c'est peut être une idée utile d'indiquer ses incl, non ?

Sylvain.

Avatar
Sylvain
kanze wrote on 06/07/2006 12:07:

Non plus. Pourquoi toutes ces manipulations numériques ?


si je t'indique que c'est pour satisfaire à l'énoncé, je pense que tu ne
comprendras pas plus.

il fait beaucoup de calculs supplémentaires pour rien.


cites-en seulement un !

[............] Mais rien ne dit que snprintf n'appelle pas
std::ostringstream.


"rien" ... enfin sauf le code source du runtime (ou bcp plus accessible
des std lib), non ?

char buffer[ sizeof( long ) * CHAR_BIT ] ;


surréservation inutile (soit, la pile survivra) et basée sur rien,
pourquoi CHAR_BIT/2 octets par digit? il en faut 1 ou 2; qu'advient-il
si la séparateur est ".-.-.-.-." et non plus " " ?

sprintf( buffer, "%d", value ) ;
Ensuite, on insère les espaces où voulu.


en couteuse recopie ? pas terrible comme solution.

On a déjà compris ici. Tu n'as pas envie d'apprendre de
nouvelles techniques. Quoiqu'elles puissent apporter.


pouf, pouf, ben alors non, "on" n'a encore pas tout compris.

Sylvain.

Avatar
Falk Tannhäuser
Sylvain wrote:
sprintf( buffer, "%d", value ) ;
Ensuite, on insère les espaces où voulu.


en couteuse recopie ? pas terrible comme solution.


Coûteuse en temps d'exécution, par rapport aux log10(), pow(),
sprintf() multiples et diverses multiplications et divisions
(non remplaçables par des simples décalages...) ?
Autre question : Qu'est-ce qui nous garantit que log10(1000)
ne donne pas par exemple 2.99999999999999956 sur certains systèmes
- valeur qui sera arrondie à 2 lors de la conversion en int ?

Falk


Avatar
Sylvain
Falk Tannhäuser wrote on 07/07/2006 01:00:

Coûteuse en temps d'exécution, par rapport aux log10(), pow(),
sprintf() multiples


log10 et pow sont couteuses, donc je les ai utilisé une fois (pas de
"multiples" fois).

sprintf est, dans le source de mon CRT, la primitive utilisée par tous
les injecteurs de ostream (sauf <<(char*) qui copie direct.t) si c'est
couteux c'est hélas pour tout le monde.

diverses multiplications et divisions
(non remplaçables par des simples décalages...) ?


oulaaaa, mais c'est strictement interdit ici - tu vois James,
"j'apprends" ;)

Autre question : Qu'est-ce qui nous garantit que log10(1000)
ne donne pas par exemple 2.99999999999999956 sur certains systèmes
- valeur qui sera arrondie à 2 lors de la conversion en int ?


en effet, on préférera un log10(value + 1)
(l'erreur plus systématique est ici log(0)).

Sylvain.

Avatar
Arnaud Debaene
"Sylvain" a écrit dans le message de news:
44ad7f56$0$832$
Arnaud Debaene wrote on 06/07/2006 08:13:



et tu l'as testé avec les include idoines, comme mon vocabulaire de base
se limite à stdio.h et string.h, ça ne pouvoit pas compiler tout seul -
c'est peut être une idée utile d'indiquer ses incl, non ?


#include <iostream>
#include <locale>

Ceci-dit, tu n'as pas indiqué les tiens non plus ;-)

Et puis, quand tu dis que tu ne connas pas std::cout, comment dire.... Ta
crédibilité en prend un peu un coup en ce qui concerne le C++...

Arnaud


1 2 3 4