Fonction pow

Résolu
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014 - Modifié par BunoCS le 19/02/2014 à 10:49
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 - 24 févr. 2014 à 16:57
Bonjour,
je cherche à décomposer un entier dans un tableau.
J'ai pensé à utiliser la fonction pow, en enlevant à chaque fois k*pow(10,j), et j'ai une différence sur les unités, qui décrémentent inexplicablement. Je joins une partie du code, pour que vous me disiez si vous voyez le soucis, ou si vous avez une meilleure idée, sachant que je débute en C++, et que ce sujet est le premier devoir (CNED).
Merci d'avance pour le temps et l'aide apportés,


  //décomposition du nombre dans le tableau
while(nb!=0){
    for (j=8;j>=1;j--){
        k=0;
        while(nb-k*pow(10,j)>=pow(10,j)-0)
        {
            k++;
        }
        tab[j]=k;
        nb=nb-(k*pow(10,j));
    }
}
tab[0]=nb;

16 réponses

BunoCS Messages postés 15472 Date d'inscription lundi 11 juillet 2005 Statut Modérateur Dernière intervention 25 mars 2024 103
19 févr. 2014 à 11:24
Hello,

C'est bien, tu gardes ton sens de l'humour ;)
Bon, ça m'a l'air complexe ton truc... Naïvement, je le ferais avec des divisions par 10 et des modulo 10:
- le modulo te permet de récupérer le chiffre des unités
- la division te permet de "déplacer" tes chiffres vers la droite

Comprends-tu ce que je veux dire?
1
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
19 févr. 2014 à 12:54
Bonjour.

Tout d'abord, si tu débutes en C++, un petit conseil sur une erreur très classique: Évite les using namespace, voir: http://0217021.free.fr/portfolio/axel.berardino/articles/bon-usage-using-namespace

Pour ton problème, tu n'as pas besoin de tableau, ni de puissance. Je pense que tu es parti "très loin", et que tu as fortement complexifié un problème très simple. Ce n'est pas grave, ça arrive. En revanche, si ça fait vraiment 15 jours que tu dessus, c'est dommage de ne pas être venu plus tôt. Parfois, on reste bloqué sur une solution, et un oeil externe peut aider à débloquer rapidement la situation. Pour les prochaines fois, n'hésite pas à venir si tu vois que tu dépasses les 24h sur un problème donné, on t'aidera avec grand plaisir.

Ce qu'on te demande au final, si on reformule un peu, c'est d'afficher les chiffres de la droite vers la gauche, tout en les numérotant.
Si tu affiches déjà les chiffres de la droite vers la gauche, tu verras que tu auras fait 80% du problème.

Pour afficher le dernier chiffre d'un nombre on utilise nb % 10. Exemple: 123456 % 10 => 6.
Pour supprimer le dernier chiffre d'un nombre, on utilise nb / 10. Exemple: 123456 / 10 => 12345.

Avec une boucle bien placée, je pense que tu peux aisément afficher les chiffres d'un nombre de la droite vers la gauche. Puis tu ajoutes un compteur à tout ça, et tu auras ton "poid".

__________________________________________________________________________________________________
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
1
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 19/02/2014 à 13:58
Je te propose 3 solutions alternatives, de la plus simple à la plus compliquée. (Tu n'as pas vraiment besoin de pow).

La première solution, considère que l'on ne met qu'un poids sur chaque chiffre, naïvement:
#include <iostream>

int main()
{
  bool stop = false;

  while (!stop)
  {
    unsigned long int nb;
    std::cout << "Entrez un nombre, 0 pour quitter" << std::endl;
    std::cin >> nb;
    if (nb == 0)
      stop = true;
    else
    {
      unsigned int i = 0;
      while (nb != 0)
      {
         std::cout << (nb % 10) << " " << i << std::endl;
        ++i;
         nb /= 10;
      }
    }
  }

  return 0;
}



La deuxième solution, respect la consigne (affichage de chacun des poids par chiffres). On utilise un tableau fixe contenant un tableau à taille dynamique automatique (std::vector<unsigned int>).
#include <iostream>
#include <vector>

int main()
{
  bool stop = false;

  while (!stop)
  {
    std::vector<unsigned int> tab[10];
    unsigned long int nb;
    std::cout << "Entrez un nombre, 0 pour quitter" << std::endl;
    std::cin >> nb;
    if (nb == 0)
      stop = true;
    else
    {
      unsigned int i = 0;
      while (nb != 0)
      {
         tab[nb % 10].push_back(i);
         ++i;
          nb /= 10;
      }

      for (unsigned int k = 0; k < 10; ++k)
      {
         if (!tab[k].empty())
        {
           std::cout << k;
           for (unsigned int j = 0; j < tab[k].size(); ++j)
             std::cout << " " << tab[k][j];
           std::cout << std::endl;
        }
      }
    }
  }

  return 0;
}


Enfin, le troisième exemple est une solution plus généraliste. Elle fonctionne avec n'importe quelle chiffre, ou même nombre. Elle montre l'usage que l'on peut faire d'une table de "hash" (via std::map). On a une std::map qui associe un std::vector à un chiffre. C'est la solution la plus élégante, et la plus pure "C++" (pas d'introduction de C).
#include <iostream>
#include <vector>
#include <map>

int main()
{
  typedef std::map<unsigned int, std::vector<unsigned int> > map_type;
  typedef map_type::const_iterator iter;

  bool stop = false;

  while (!stop)
  {
    map_type map;
    unsigned long int nb;
    std::cout << "Entrez un nombre, 0 pour quitter" << std::endl;
    std::cin >> nb;
    if (nb == 0)
      stop = true;
    else
    {
      unsigned int i = 0;
      while (nb != 0)
      {
         map[nb % 10].push_back(i);
        ++i;
         nb /= 10;
      }

      for (iter it = map.begin(); it != map.end(); ++it)
      {
         std::cout << it->first;
         for (std::vector<unsigned int>::const_iterator jt = it->second.begin(); jt < it->second.end(); ++jt)
           std::cout << " " << *jt;
         std::cout << std::endl;
      }
    }
  }

  return 0;
}


__________________________________________________________________________________________________
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
1
BunoCS Messages postés 15472 Date d'inscription lundi 11 juillet 2005 Statut Modérateur Dernière intervention 25 mars 2024 103
Modifié par BunoCS le 19/02/2014 à 10:51
Hello,
J'ai édité ton message pour rajouter les balises code. Plus d'infos ici. Merci d'y penser la prochaine fois ;)

Tu cherches à faire quoi exactement? C'est quoi nb, k, tab?

@+
Buno, Modo CS-CCM
L'urgent est fait, l'impossible est en cours. Pour les miracles, prévoir un délai...
The urgent is done, the impossible is underway. For miracles, envisage a time ...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014
19 févr. 2014 à 11:10
Bonjour Bruno et merci de ton aide, j'ai fait un copier-merder, euh... coller pardon, je ferais attention la prochaine fois aux balises.
nb est un unsigned long int, limité par l'énnoncé à cette taille, et les autres variables sont des int.
Le but de l'exo est d'afficher le poids de chaque chiffre d'un nombre:
exemple, pour 234456, 6 a pour poids 0, 5 a un poids de 1, 4 a un poids de 2 et 3, 3 a un poids de 4 et 2 un poids de 5. (en parlant de poids, j'espère ne pas être trop lourd :)).
Voilà pourquoi je voulais "ranger " chaque chiffre du nombre entier dans un tableau, pour utiliser et analyser plus facilement ensuite.
J'y suis depuis 15 jours et sur la décomposition, en suivant pas à pas, j'ai parfois une erreur de 1 sur le calcul de nb-k*pow(10,j), et mathématiquement cela ne me parait pas logique.
J'ai vu sur les topics de pow une histiore de "float", mais là, c'est moi qui coule...
merci encore,
Laurent
0
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014
19 févr. 2014 à 11:26
je met l'ensemble si certains veulent bien critiquer, car ce sont mes toutes premières lignes de code, et j'ai bien conscience qu'il doit y avoir moyen d'optimiser...
En plus, je m'entraine pour mettre les balises :)

//programme affichage poids des chiffres dans un nombre
#include <iostream>
#include <math.h>

using namespace std;

int main()
{
//déclarations et initialisations
unsigned long int nb,nbr;
int tab[9],i,j,k,u,m,r;

//saisie du nombre initial, sortie pour 0
cout <<"entrez un nombre, 0 pour quitter"<<endl;
cin>>nb;
//décomposition du nombre dans le tableau
while(nb!=0){
for (j=8;j>=1;j--){
k=0;
while(nb-k*pow(10,j)>=pow(10,j)-0)
{k++;
}
tab[j]=k;
nb=nb-(k*pow(10,j));
}
}
tab[0]=nb;
//valeurs du tableau non utilisées égales à 10
r=8;
while(tab[r]==0)
{tab[r]+=10;
r--;
}

//affichage du poids de chaque chiffre
for (i=0;i<=8;i++){
if (tab[i]<10){
cout<<tab[i]<<" "<<i<<" ";
for (u=i+1;u<=8;u++){
if (tab[i]==tab[u]){
cout<<u<<" ";
tab[u]+=10;}
}
cout<<endl;
}
}
//reconstitution du nombre
nbr=0;
for (m=0;m<=8;m++){
if (tab[m]>=10){
tab[m]-=10;
}
nbr+=tab[m]*pow(10,m);
}
nbr+=1;
cout<<nbr<<endl;
cout<<"entrez un nombre, 0 pour arrêter: ";
cin>>nb;
}
return 0;
}

                
0
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014
19 févr. 2014 à 11:33
Je crois que je comprends, avec les divisions par 10 et modulo, je décompose dans l'autre sens, en partant des unités, non?
Cela devrait en plus simplifier la deuxième partie.
Je tente et je reposte, merci en tous cas pour la piste :)
0
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014
19 févr. 2014 à 12:58
La division par 10 et l'affectation du reste dans le tableau marche nikel, et ça évite une boucle, merci beaucoup, moi aussi quand je serais grand, je saurais coder :)

Laurent, 43 ans, 1m65, mais motivé comme un jeune!
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
19 févr. 2014 à 13:09
N'hésite pas à poster ta solution ici, afin que l'on puisse l'améliorer, ou te conseiller des solutions alternatives.

__________________________________________________________________________________________________
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
0
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014
19 févr. 2014 à 13:20
//programme affichage poids des chiffres dans un nombre
#include <iostream>
#include <math.h>

using namespace std;

int main()
{
//déclarations et initialisations
unsigned long int nb,nbr;
int tab[9],i,j,k,l,m;

//saisie du nombre initial, sortie pour 0
cout <<"entrez un nombre, 0 pour quitter"<<endl;
cin>>nb;
//décomposition du nombre dans le tableau
while(nb!=0){
for (j=0;j<=8;j++)
{tab[j]=nb%10;
nb/=10;
}
//valeurs du tableau non utilisées égales à 10
l=8;
while(tab[l]==0)
{tab[l]+=10;
l--;
}

//affichage du poids de chaque chiffre
for (i=0;i<=8;i++){
if (tab[i]<10){
cout<<tab[i]<<" "<<i<<" ";
for (k=i+1;k<=8;k++){
if (tab[i]==tab[k]){
cout<<k<<" ";
tab[k]+=10; }//permet de ne pas réutiliser ce chiffre
}
cout<<endl;}
}
//reconstitution du nombre
nbr=0;
//réinitialisation du tableau aux valeurs d'origine
for (m=0;m<=8;m++){
if (tab[m]>=10){
tab[m]-=10;
}
nbr+=tab[m]*pow(10,m);
}
cout<<nbr<<endl;
cout<<"entrez un nombre, 0 pour arrêter: ";
cin>>nb;
}
return 0;
}



voilà, ma prose complète, si il ya des suggestions et critiques, je prends,
merci,
Laurent
0
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014
19 févr. 2014 à 13:32
Merci cptpingu,
il y avait une partie de l'énnoncé que je n'ai pas donné, c'est le format de l'affichage, qui devait être:
pour le nombre 34546 par exemple:
6 0
4 1 3
5 2
3 4
34546

(avec reconstitution du nombre à la fin)
Là, je crois que j'ai tout dit.
Cela fait vraiment plaisir de voir la solidarité que l'on trouve sur ce forum, et je n'hésiterai pas à reposter. Ceci dit, je trouve que se "creuser les méninges" m'aide à progresser. Ce qui est sur, c'est que 15 jours, c'était trop long, et j'appellerai à l'aide plus tôt.

A trés bientôt donc (la lucidité de mon grand âge :))
Laurent
0
dubs2a Messages postés 8 Date d'inscription mercredi 19 février 2014 Statut Membre Dernière intervention 19 février 2014
19 févr. 2014 à 16:32
Merci bcp, cptpingu,
je vais décortiquer les trois solutions, la deuxième étant d'aprés moi la plus en phase avec l'état d'avancement de mon cours, et la troisième représentant un pas supplémentaire pour moi. La première me montre qu'un problème peut être plus simple qu'il ne parait, et qu'il ne faut pas scléroser sur une "manière".
Mon but est bien sur de progresser, et ces posts m'auront bien aidé.
J'espère juste qu'un jour je pourrais aider un débutant C++, avant d'avoir besoin d'un déambulateur...
Je le dis beaucoup, mais je le pense: MERCI.
0
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
21 févr. 2014 à 23:26
Salut,

L'affichage du résultat formaté est plus compliqué que le calcul des valeurs !
On a tendance a faire 4, 5 ou même 6 boucles dont certaines imbriquées !

Une autre solution plus orienté C que C++ en utilisant la valeur ascii des caractères et pas le calcul /10 et %10

On est pas dans l'"élégance" mais le résultat est là.
Si le prof. note le résultat, pas de problème, si il note une "manière orthodoxe" de faire, alors c'est pas bon.

void main()
{
	/*
		Exemple, si saisie 1234445555 affiche
		5	0	1	2	3
		4	4	5	6
		3	7
		2	8
		1	9
	*/
	const int MAXSIZENUM = (int)log10((double)INT_MAX)+1;/*<limit.h> largeur max pour 1 int*/
	char* buf = new char[MAXSIZENUM]; /*le nombre saisi*/
	int sizeStr; /*la taille du nombre*/

	while(true)
	{
		printf("le nombre (0 pour quitter ): ");
		scanf("%s", buf);
		sizeStr = strlen(buf);
		if(!strcmp(buf,"0")) break;

		buf = strrev(buf); /* Reverse string */
	
		int* pVals= new int[sizeStr]; /* Les chiffres */
		int* pPoids = new int[MAXSIZENUM];	/* Les poids */
		memset(pPoids, -1, sizeof(int)*MAXSIZENUM); 

		int savInd = -1, rechVal = -1; /* pseudo curseur dans la boucle */
		for(int i=0; i<sizeStr; i++)
		{
			pVals[i] = (int)buf[i]-48; /*Le chiffre en cours*/
			if(rechVal == -1 && pPoids[ pVals[i] ] == -1) /*pas encore de poids*/
			{
				pPoids[ pVals[i] ] = i;
				rechVal = pVals[i] ; 
				printf("\r\n%d \t%d", pVals[i], pPoids[ pVals[i] ]);
			}
			else
			{
				if( rechVal == -1 && savInd==-1 )
					savInd = i;
				else if( pVals[i] == rechVal) /* même poids, même ligne */
					printf("\t%d", i);
			}
			if(i == sizeStr-1) /* réinit */
			{
				i=savInd; rechVal=-1; savInd=-1;
			}
		}

		delete[] pVals;
		delete[] pPoids;
		printf("\r\n%s\r\n", strrev(buf));
	}
}


bye...
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 22/02/2014 à 00:08
La solution proposée par yann_lo_san fonctionne, mais je la déconseille fortement ! Ce qui est demandé est un classique: on a un nombre, on le décompose via des "%" et des "/", c'est simple, rapide et efficace. Ca c'est pour la partie algorithmie. yann_lo_san précise tout de même que ce n'est pas nécessairement la meilleure approche. Ca reste une méthode alternative (et donc intéressante), mais il y a beaucoup de petites choses qui me gênent dans ce code.

@yann_lo_san:
Le problème de ta solution n'est pas "l'élégance". Ce qui est gênant, c'est que tu "tournes autour du pot" pour réaliser quelque chose de très directe. J'entends par là, que tu réalises de nombreuses opérations inutiles.

Analysons techniquement la méthode que tu proposes:
- Tout d'abord, tu représentes un nombre par une chaîne de caractères qui va être bien plus grande en mémoire que si ça avait été mis dans un entier (certes techniquement à ce stade ce n'est pas un vrai problème). Mais c'est tout de même mieux de montrer à un débutant d'utiliser les bons types. Ignorons ce détail, puisque tu précises bien que c'est pour montrer une méthode différente (ce qui est tout à ton honneur).
- Là où ça devient plus gênant: Tu fais un "strlen". On perd donc une passe sur la chaîne pour rien. En effet, scanf te retourne le nombre de caractères lus... Donc indirectement la taille de ta chaîne (c'est vrai pour un cas aussi simple).
- Ensuite, tu perds du temps à faire un "strrev" (en gros retourner la chaîne), alors qu'il suffit simplement de faire une boucle de la fin vers la début. En plus de cela, tu inverses la chaîne de nouveau à la fin pour la remettre à "l'endroit" (ce qui n'est pas nécessaire si tu ne la retournes pas au début).
- "const int MAXSIZENUM = (int)log10((double)INT_MAX)+1;" => Etant donné que les chiffres vont de 0 à 9, je pense qu'on peut se permettre de considérer qu'il y a 10 chiffres possibles et donc écrire directement "const int MAXSIZENUM = 10". Si on veut pinailler, on aurait pu aussi aller plus loin et écrire "const uint8_t MAXSIZENUM = 10" (ce qui équivaut à un unsigned char).

Quelques petits détails supplémentaires:
- pVals[i] = (int)buf[i]-48; => Le "cast" en int n'est pas nécessaire. (Je ne suis pas sur qu'un seul cast soit nécessaire d'ailleurs dans ton code).
- void main() => Attention, c'est officiellement "int main()". Le main retourne une valeur, qui est la code d'erreur lors de la fin du programme. On considère généralement le "void main" comme une extension non officielle et non standard (bien que supportée par certains compilateurs, si on n'active pas le mode "strict").

__________________________________________________________________________________________________
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
0
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
24 févr. 2014 à 13:21
Salut,

oui, oui, je prends toutes tes remarques à 100%.
Je m'était concentré sur le fait de ne faire qu'une seule boucle,
tout ce qui se trouve autour était codé "à la va vite"... pour construire l'exemple.

Par contre j'ai testé ton exemple 3 avec le std::map<> dont l'approche est bien sympa, mais il me semble qu'il y a une petite coquille

Si je saisi par exemple : 33442211
la sortie est :
1 0 1
2 2 3
3 6 7
4 4 5

les 2 dernières lignes sont inversées (comme triées)

Peut être que l'objet map<> tri ? a voir...

Bye...
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
24 févr. 2014 à 16:57
L'exemple 3, conserve l'ordre via l'operateur implicite "operator<" (utilisé par std::map en interne). Le std::map est une structure d'arbre ordonnée (donc triée).
Si on ne veut pas conserver l'ordre, il faut utiliser un std::unordered_map (mais alors aucun ordre n'est garanti, pas même l'ordre d'insertion). Je ne l'ai pas non plus utilisé car ce n'est disponible qu'en C++11.
La méthode qui se rapproche le plus de la consigne est évidemment la 2. Les autres méthodes ne respectent pas parfaitement l'affichage.

__________________________________________________________________________________________________
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
0
Rejoignez-nous