OVH Cloud OVH Cloud

1/2 newbie en c++ : formatage des reels

26 réponses
Avatar
Bonjour,

je suis en train d'apprendre la stl, le bouquin de jossutis est presque
parfait mais certains points restent obscurs.

Par exemple :

1)
en pascal write(123.456) renvoie 123.456.
et write(123.456:7:4") renvoie 123.4560

en c++ "cout << 123.456" renvoie 123.456000
cout << setprecision(0) << 123.456 renverra 123
... etc

donc on ne peut pas avoir un nombre de décimales flottant avec ostream
c'est bien ça ?

et il n'y a pas d'équivalent de sprintf en c++ à part ostringstream

j'ai tout compris ou je me plante ?

merci d'avance

Alain

10 réponses

1 2 3
Avatar
Michel Michaud
Dans news:413cbf11$0$309$, @(none)"
en pascal write(123.456) renvoie 123.456.


Vraiment ? C'est un hasard intéressant...

et write(123.456:7:4") renvoie 123.4560

en c++ "cout << 123.456" renvoie 123.456000
cout << setprecision(0) << 123.456 renverra 123
... etc

donc on ne peut pas avoir un nombre de décimales flottant avec
ostream c'est bien ça ?


Que veux-tu exactement ?

Essaie toujours :

cout << fixed << right << setw(10) << setprecision(4) << 123.456;

Ça donnera bb123.4560 (je mets b pour les blancs).

En jouant avec le setw et le setprecision, tu devrais pouvoir
obtenir ce que tu veux...

et il n'y a pas d'équivalent de sprintf en c++ à part
ostringstream


Pourquoi « à part ostringstream » ? Un remplacement, ça ne te
suffit pas ? (en fait, il y a aussi ostrstream, moins utile en
général)

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

Avatar

en pascal write(123.456) renvoie 123.456.
Vraiment ? C'est un hasard intéressant...



:-)

Que veux-tu exactement ?


cout << 1.23 << " - " << 1.1 << " = " << 0.13 << endl;
==> 1.23 - 1.1 = 0.13
et non
==> 1.230000 - 1.100000 = 0.130000 :-)
parce que pour l'écrire il faut

cout << fixed << setprecision(2) << 1.23 << " - " << setprecision(1) <<
1.1 << " = " << setprecision(2) << 0.13 << endl;

j'ai pris cet exemple parce qu'il montre que je dois connaitre le nombre
de décimales pour qu'il n'affiche pas de 0 inutiles.


Essaie toujours :

cout << fixed << right << setw(10) << setprecision(4) << 123.456;

Ça donnera bb123.4560 (je mets b pour les blancs).

En jouant avec le setw et le setprecision, tu devrais pouvoir
obtenir ce que tu veux...


justement, le but est d'éliminer automatiquement les décimales inutiles.
pas grave, je ferai une moulinette.

Pourquoi « à part ostringstream » ? Un remplacement, ça ne te
suffit pas ? (en fait, il y a aussi ostrstream, moins utile en
général)


parce que :
snprintf(dest, 20, "%-3d %4st%-10.2f", entier, chaine, double);

se traduit par ... un sacré paquet de code.

------------
j'en ai trouvé une autre bizarrerie :

string(source, len); // ou string(string, int)
nécessite que source ait au moins len caractères.

alors que string(source) ne rempli pas avec des caractères
aléatoires.

comment donc empêcher un buffer overflow (ou un mem overflow)
si on ne peut tronquer une string dès à la construction de la chaine ?

Alain


Avatar
Jean-Marc Bourguet
"@(none)" <""alain"@(none)"> writes:


en pascal write(123.456) renvoie 123.456.
Vraiment ? C'est un hasard intéressant...



:-)

Que veux-tu exactement ?


cout << 1.23 << " - " << 1.1 << " = " << 0.13 << endl;
==> 1.23 - 1.1 = 0.13
et non
==> 1.230000 - 1.100000 = 0.130000 :-)
parce que pour l'écrire il faut

cout << fixed << setprecision(2) << 1.23 << " - " << setprecision(1) << 1.1
<< " = " << setprecision(2) << 0.13 << endl;

j'ai pris cet exemple parce qu'il montre que je dois connaitre le nombre de
décimales pour qu'il n'affiche pas de 0 inutiles.


[~]$ cat none.cpp
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
cout << fixed
<< 1.23 << " - " << 1.1 << " = " << 0.13 << endl
<< resetiosflags(ios_base:: floatfield)
<< 1.23 << " - " << 1.1 << " = " << 0.13 << endl;
}
[~]$ g++-3.3 -W -Wall -pedantic-errors -std=c++98 -o none none.cpp
[~]$ ./none
1.230000 - 1.100000 = 0.130000
1.23 - 1.1 = 0.13

------------
j'en ai trouvé une autre bizarrerie :

string(source, len); // ou string(string, int)
nécessite que source ait au moins len caractères.

alors que string(source) ne rempli pas avec des caractères
aléatoires.

comment donc empêcher un buffer overflow (ou un mem overflow)
si on ne peut tronquer une string dès à la construction de la chaine ?


J'ai pas compris le problème.

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Avatar
Falk Tannhäuser
none wrote:

cout << 1.23 << " - " << 1.1 << " = " << 0.13 << endl;
==> 1.23 - 1.1 = 0.13
et non
==> 1.230000 - 1.100000 = 0.130000 :-)
parce que pour l'écrire il faut

cout << fixed << setprecision(2) << 1.23 << " - " << setprecision(1) <<
1.1 << " = " << setprecision(2) << 0.13 << endl;


std::cout.setf(std::ios::fixed);
std::cout << 1.23 << " - " << 1.1 << " = " << (1.23 - 1.1) << std::endl;
std::cout.unsetf(std::ios::fixed);
std::cout << 1.23 << " - " << 1.1 << " = " << (1.23 - 1.1) << std::endl;

affiche chez moi
1.230000 - 1.100000 = 0.130000
1.23 - 1.1 = 0.13

Au démarrage du programme, le flag 'std::ios::fixed' est dévalidé.


j'en ai trouvé une autre bizarrerie :

string(source, len); // ou string(string, int)
nécessite que source ait au moins len caractères.


D'après § 21.3.1/4-5, le constructeur
basic_string(const basic_string<charT,traits,Allocator>& str,
size_type pos = 0, size_type n = npos,
const Allocator& a = Allocator());
construit une chaîne dont la longueur est égale à
std::min(n, str.size()-pos) ; si pos>str.size(), l'exception
std::out_of_range est levée.

alors que string(source) ne rempli pas avec des caractères
aléatoires.


Pourquoi il le ferait ?

comment donc empêcher un buffer overflow (ou un mem overflow)
si on ne peut tronquer une string dès à la construction de la chaine ?


Comprends pas.
std::string s("Test: Hello world!");
std::string s1(s, 6, 4);
std::string s2(s, 6, 9999);
std::string s3(s, 6);

initialise s1 avec "Hell" et s2 et s3 avec "Hello world!" -
pourquoi devrait-il y avoir un buffer overflow ?

Falk

Avatar
Alain Cabiran
je répond à Jean Marc et à Falk en même temps :
(je suis passé sous windows depuis ma prédécente réponse)

cout << fixed
<< 1.23 << " - " << 1.1 << " = " << 0.13 << endl
<< resetiosflags(ios_base:: floatfield)
<< 1.23 << " - " << 1.1 << " = " << 0.13 << endl;
.....


resetiosflag et std::cout.unsetf(std::ios::fixed) donnent exactement
ce que vous dîtes et ici aussi ... sous win :-)
j'ai essayé bc 6.0 et gcc 3.3 (cygwin)
par contre sous nux que j'utilise d'habitude ça ne fonctionne pas
avec gcc 2.95 et gcc 3.0 ne donne pas toujours les bons résultat
suivant les test que je fais avec.

moralité Debian woody grrrr et ça devient hors sujet pour le groupe
je vais donc voir du côté de mon os (peut-être stlport qui sait)

comment donc empêcher un buffer overflow (ou un mem overflow)
si on ne peut tronquer une string dès à la construction de la chaine ?


J'ai pas compris le problème.


je veux faire ça (voilà que je donne mon code source maintenant :-) :

(Currency est à peu près l'équivalent de celle de BC++ sauf qu'elle
fonctionne sous Linux et est basé sur du long 32 bits et 64 quand les
cpu des pc changeront)

class Budget
{
public:
const string &category;
const string &name;
const Currency &value;

Budget(char * c, char *n, Currency v);
private:
string categorie;
string nom;
Currency valeur;
}

char * est indispensable pour des problèmes de portabilité, je converti mon
prog Qt en STL
et doit compiler sous g++ sous nux et BC sous win, (hors forum mais
précision peut être utile)

donc :

Budget::Budget(char *c, char *n; Currency v)
: category(categorie), name(nom), value(valeur)
{
categorie = string(c, 80); // oui je sais, au dessus avec les ":" ;-)
......

mon problème est que d'après le bouquin (donc la norme)
si c est trop court, ça passera pas

je peux donc essayer categorie = string(c)
imaginons maintenant que strlen(c) = 35478945231
le beau plaf du constructeur

en C, j'aurais pu faire strncpy( temp, c, 80);

en C++ je suis coincé.

si vous avez une idée ...

une dernière et je vous embête plus :
j'ai découvert random_shuffle(it, it, rand_func) ce midi et ai testé ça tout
à l"heure.
comme pour tous les random, le rnd initial est nécessaire, mais j'ai pas
trouvé
où ....

au sec. ! c'est vrai que le C++ sans Qt ni C c'est pas facile !

Alain Cabiran


Avatar
Falk Tannhäuser
Alain Cabiran wrote:

(Currency est à peu près l'équivalent de celle de BC++ sauf qu'elle
fonctionne sous Linux et est basé sur du long 32 bits et 64 quand les
cpu des pc changeront)

class Budget
{
public:
const string &category;
const string &name;
const Currency &value;

Budget(char * c, char *n, Currency v);
private:
string categorie;
string nom;
Currency valeur;
}

char * est indispensable pour des problèmes de portabilité, je converti mon


AMA plutôt 'char const*' ? Sinon tu ne pourras pas passer des chaînes constantes...

prog Qt en STL
et doit compiler sous g++ sous nux et BC sous win, (hors forum mais
précision peut être utile)

donc :

Budget::Budget(char *c, char *n; Currency v)
: category(categorie), name(nom), value(valeur)
{
categorie = string(c, 80); // oui je sais, au dessus avec les ":" ;-)
......

mon problème est que d'après le bouquin (donc la norme)
si c est trop court, ça passera pas
Donc c'est le constructeur

basic_string(const charT* s, size_type n,
const Allocator& a = Allocator());
qui sera appelé (cf § 21.3.1/6-8).
Apparemment tu cherches
: ..., categorie(c, std::min(std::strlen(c), std::size_t(80)))


je peux donc essayer categorie = string(c)
imaginons maintenant que strlen(c) = 35478945231
le beau plaf du constructeur


Ton 'c' vient d'où alors ? L'intérêt des std::string est justement de ne pas être
obligé de couper les chaînes à cause d'utilisation des buffeurs de taille fixe !
Par contre, si 'c' est un pointeur invalide (NULL, non initialisé ou pointant
sur une zone de mémoire libérée), effectivement ça se passera mal...


en C, j'aurais pu faire strncpy( temp, c, 80);
en C++ je suis coincé.
si vous avez une idée ...


Voir ci-dessus.


une dernière et je vous embête plus :
j'ai découvert random_shuffle(it, it, rand_func) ce midi et ai testé ça tout
à l"heure.
comme pour tous les random, le rnd initial est nécessaire, mais j'ai pas
trouvé
où ....


Tu peux simplement appeler std::random_shuffle(it_begin, in_end) mais ni
le générateur de nombres aléatoires ni la façon d'initialiser son seed
sont spécifiés dans la Norme (§ 25.2.11). Si le résultat n'est pas assez
aléatoire pour toi, tu peux utiliser ton propre générateur qui gère son
seed. Exemple (il y en a d'autres sur le Web) :
_________________________________________________________________________
#include <algorithm>
#include <iostream>
#include <ostream>
#include <iterator>

// See <http://www.gnu.org/software/gsl/manual/gsl-ref_17.html>,
// "Generator: gsl_rng_knuthran2"
class SuperDuperRng
{
static unsigned long long const a1 = 271828183;
static unsigned long long const a2 = 314159269;
static unsigned long long const m = (1UL << 31) - 1;
unsigned long xn, xn_1;

public:
SuperDuperRng(unsigned long u1, unsigned long u0=0)
: xn(u1), xn_1(u0)
{
if(xn==0 && xn_1==0)
xnG11; // Won't get very random numbers otherwise
}

static unsigned long RandMax() { return m; }
int operator()()
{
unsigned long xn_new = (a1 * xn + a2 * xn_1) % m;
xn_1 = xn; xn = xn_new;
return xn;
}
unsigned long operator()(unsigned long max)
{
unsigned long rem = (m + 1) % max;
unsigned long pseudorand = operator()();
while(pseudorand > m - rem)
pseudorand = operator()();
return pseudorand % max;
}
}; // class SuperDuperRng

int main()
{
int iarr[10]; for(int i=0; i<10; ++i) iarr[i] = i;
SuperDuperRng rng(42, 666); // Or any seed you like
for(int i=0; i<10; ++i)
{
std::random_shuffle(iarr, iarr+10, rng);
std::copy(iarr, iarr+10, std::ostream_iterator<int>(std::cout));
std::cout << 'n';
}
___________________________________________________________________

Falk

Avatar
kanze
"Alain Cabiran" wrote in message
news:<413e1476$0$313$...
je répond à Jean Marc et à Falk en même temps :
(je suis passé sous windows depuis ma prédécente réponse)

cout << fixed
<< 1.23 << " - " << 1.1 << " = " << 0.13 << endl
<< resetiosflags(ios_base:: floatfield)
<< 1.23 << " - " << 1.1 << " = " << 0.13 << endl;
.....


resetiosflag et std::cout.unsetf(std::ios::fixed) donnent exactement
ce que vous dîtes et ici aussi ... sous win :-)
j'ai essayé bc 6.0 et gcc 3.3 (cygwin)
par contre sous nux que j'utilise d'habitude ça ne fonctionne pas
avec gcc 2.95 et gcc 3.0 ne donne pas toujours les bons résultat
suivant les test que je fais avec.


J'ai essayé avec g++ 2.95.2 -- ça marche chez moi. Sauf qu'évidemment,
les manipulateurs fixed et resetiosflag n'existent pas. Il faut écrire
plutôt :
cout.setf( ios::fixed, ios::floatfield ) ;
et
cout.unsetf( ios::floatfield ) ;

Question de style, c'est probablement mieux de faire ainsi de toute
façon. Les flags en question sont persistents, alors que l'utilisation
d'un manipulateur suggère (au moins à moi) que l'opération ne vaut que
pour cette expression.

Dans la pratique, j'utilise prèsqu'exclusivement mes propres
manipulateurs, qui permettent d'écrire des choses comme :

cout << 123.456 << 'n' ; // affiche 123.456
cout << FFmt( 10.6 ) << 123.456 << 'n' ;
// affiche 123.456000
cout << 123.456 << 'n'; // affiche 123.456

Sinon, évidemment, il y a la classe (non-standard) Format :

cout << Format( "%10.6f" ).with( 123.456 ) << 'n' ;

Pas très intéressant pour une seule valeur, mais pour des choses comme :

cout << Format( "%d %s valent %.2f" )
.with( count ).with( name ).with( value ) << 'n' ;

Surtout si par la suite, on fait traduire, et l'ordre des champs n'est
pas le même :

cout << Format( "%3$.2f tnelav %2$s %1$d" )
.with( count ).with( name ).with( value ) << 'n' ;

(Normalement, évidemment, la chaîne de formattage est obtenu par un
appel à gettext() ou son équivalent.)

Les classes en question sont disponible à ma site.

--
James Kanze GABI Software http://www.gabi-soft.fr
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
Jean-Marc Bourguet
"Alain Cabiran" writes:

par contre sous nux que j'utilise d'habitude ça ne fonctionne pas
avec gcc 2.95 et gcc 3.0 ne donne pas toujours les bons résultat
suivant les test que je fais avec.

moralité Debian woody grrrr et ça devient hors sujet pour le groupe
je vais donc voir du côté de mon os (peut-être stlport qui sait)


Ce pourrait etre aussi un probleme de precision dans les calculs
puisque tu as l'air d'indiquer que tu as le resultat desire ou pas
suivant les valeurs.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
kanze
Falk Tannhäuser wrote in message
news:<413e36a7$0$288$...
Alain Cabiran wrote:

(Currency est à peu près l'équivalent de celle de BC++ sauf qu'elle
fonctionne sous Linux et est basé sur du long 32 bits et 64 quand
les cpu des pc changeront)

class Budget
{
public:
const string &category;
const string &name;
const Currency &value;



Pour commencer, c'est quoi, c'est membre référence ? Les membres
références sont normalement rarissime. (De même que les membres donnés
publiques, d'ailleurs, dans une class qui a aussi des membres privés.)

Budget(char * c, char *n, Currency v);
private:
string categorie;
string nom;
Currency valeur;
}

char * est indispensable pour des problèmes de portabilité, je
converti mon


AMA plutôt 'char const*' ? Sinon tu ne pourras pas passer des chaînes
constantes...

prog Qt en STL et doit compiler sous g++ sous nux et BC sous win,
(hors forum mais précision peut être utile)

donc :

Budget::Budget(char *c, char *n; Currency v)
: category(categorie), name(nom), value(valeur)
{
categorie = string(c, 80); // oui je sais, au dessus avec les ":" ;-)
......

mon problème est que d'après le bouquin (donc la norme)
si c est trop court, ça passera pas


Donc c'est le constructeur
basic_string(const charT* s, size_type n,
const Allocator& a = Allocator());
qui sera appelé (cf § 21.3.1/6-8).
Apparemment tu cherches
: ..., categorie(c, std::min(std::strlen(c), std::size_t(80)))


Voire simplement categorie( s ).

je peux donc essayer categorie = string(c)
imaginons maintenant que strlen(c) = 35478945231
le beau plaf du constructeur


Ton 'c' vient d'où alors ? L'intérêt des std::string est justement de
ne pas être obligé de couper les chaînes à cause d'utilisation des
buffeurs de taille fixe ! Par contre, si 'c' est un pointeur invalide
(NULL, non initialisé ou pointant sur une zone de mémoire libérée),
effectivement ça se passera mal...


C'est vrai que quelques coups de string(c) avec un c où strlen(c) vaut
35478945231, ça pourrait poser des problèmes sur beaucoup de systèmes.
Du genre bad_alloc. D'ailleurs, l'existance même d'une chaîne (C ou
std::string) de cette taille est impossible sur pas mal des machines.

Si le poster a réelement à gerer des chaînes de cette longueur, il se
peut bien qu'il a besoin des moyens spéciaux.

en C, j'aurais pu faire strncpy( temp, c, 80);
en C++ je suis coincé.
si vous avez une idée ...



On aimerait d'abord comprendre le problème.

Voir ci-dessus.

une dernière et je vous embête plus :
j'ai découvert random_shuffle(it, it, rand_func) ce midi et ai testé ça tout
à l"heure.
comme pour tous les random, le rnd initial est nécessaire, mais j'ai pas
trouvé
où ....


Tu peux simplement appeler std::random_shuffle(it_begin, in_end) mais
ni le générateur de nombres aléatoires ni la façon d'initialiser son
seed sont spécifiés dans la Norme (§ 25.2.11). Si le résultat n'est
pas assez aléatoire pour toi, tu peux utiliser ton propre générateur
qui gère son seed. Exemple (il y en a d'autres sur le Web) :


Chez Boost, par exemple, où à ma site.

_________________________________________________________________________
#include <algorithm>
#include <iostream>
#include <ostream>
#include <iterator>

// See <http://www.gnu.org/software/gsl/manual/gsl-ref_17.html>,
// "Generator: gsl_rng_knuthran2"
class SuperDuperRng
{
static unsigned long long const a1 = 271828183;
static unsigned long long const a2 = 314159269;
static unsigned long long const m = (1UL << 31) - 1;
unsigned long xn, xn_1;

public:
SuperDuperRng(unsigned long u1, unsigned long u0=0)
: xn(u1), xn_1(u0)
{
if(xn==0 && xn_1==0)
xnG11; // Won't get very random numbers otherwise


On voit l'allemand:-). Dans les milieux internationaux, 42 est la valeur
préférée, mais les allemands semblent préférer 4711.

Personnellement, j'aurais pris « time( NULL ) ».

--
James Kanze GABI Software http://www.gabi-soft.fr
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
Samuel Krempp
le Wednesday 08 September 2004 10:26, écrivit :

C'est vrai que quelques coups de string(c) avec un c où strlen(c) vaut
35478945231, ça pourrait poser des problèmes sur beaucoup de systèmes.
Du genre bad_alloc. D'ailleurs, l'existance même d'une chaîne (C ou
std::string) de cette taille est impossible sur pas mal des machines.


oui, et je trouve que "string(c)" est la bonne chose à faire.
si c est une chaine incroyablement trop longue parceque le pointeur est en
fait non-initialisé, ça fera une exception. Je pense qu'il n'y a de toute
façon pas grand chose à faire à l'intérieur de la classe, dans cette
situation..

Si le poster a réelement à gerer des chaînes de cette longueur, il se
peut bien qu'il a besoin des moyens spéciaux.


c'est le moins qu'on puisse dire :)

Dans les milieux internationaux, 42 est la valeur
préférée, mais les allemands semblent préférer 4711.


ça m'intrigue, autant je connais 42, autant je ne vois pas du tout d'où
vient 4711...
Qu'est ce que c'est que ce nombre ??

--
Sam

1 2 3