Aller au contenu

[C++] Norme d'un vecteur en C++


_NoA_

Messages recommandés

Bonjour à tous.

Je dois rendre un projet en C++ dans lequel j'ai besoin de calculer une norme de vecteur, le problème c'est que le programme que j'ai conçu ne donne pas de bon résultat pour les vecteurs à composantes décimales.

Voici comment je calcule la norme:

#include<string>
#include<iostream>
#include<vector>
#include<math.h>
using namespace std;

void remplvect(vector<float> &b,int n)
{
    cout<<"Saisir le vecteur :"<<endl;
    for (int i=0;i<n;i++)
    {
        cin>>b[i];
        }
    cout<<endl;
    }

float norme(vector<float> u,float ν, int n)
{
   int p=0;
   for(int i=0;i<n;i++)
   {
       p=u[i]*u[i]+p;
   }
   nu=sqrt(p);
}

int main()
{
   int n=3;
   float nu;
   vector<float> u;
   u.resize(n);
   remplvect(u,n);
   norme(u,nu,n);
   cout<<"norme : "<<nu<<endl;
}

Par exemple pour le vecteur [0.75,0.5,0.25] il me rend la valeur 0 au lieu de 0.9354...

Je me suis dit que c'était un problème de type de variable mais je ne vois pas lequel.

Merci à ceux qui m'aideront :ouioui:

Lien vers le commentaire
Partager sur d’autres sites

T'as pris un int pour la variable p, alors qu'il va recevoir du float.

Ta fonction norme a un problème de retour, tu devrais faire un return nu ou la typer void norme(blabl...)

Ca m'étonne que tu puisse compiler comme ça d'ailleurs

Effectivement c'était bête, j'ai pas pensé à vérifier la variable p :transpi: . Je n'ai commencé le C++ que le mois dernier alors j'ai pas encore bien compris à quoi sert exactement le return ou le type devant le nom de la fonction, je vais me documenter là-dessus :chinois:

Merci en tout cas de m'avoir débloqué :byebye:

Lien vers le commentaire
Partager sur d’autres sites

le return type, c'est ce que retourne ta fonction à la fin de l'exécution. Par exemple, tu peux faire ça dans ton code :

#include<string>
#include<iostream>
#include<vector>
#include<math.h>
using namespace std;

void remplvect(vector<float> &b,int n)
{
	cout<<"Saisir le vecteur :"<<endl;
	for (int i=0;i<n;i++)
	{
    	cin>>b[i];
    	}
	cout<<endl;
	}

float norme(vector<float> u, int n)
{
   float p=0f; // type float

   for(int i=0;i<n;i++)
   {
       p=u[i]*u[i]+p;
   }
   return sqrt(p); // On renvoie la norme du vecteur
}

int main()
{
   int n=3;
//float nu;
   vector<float> u;
   u.resize(n);
   remplvect(u,n);
   //norme(u,nu,n);
   cout<<"norme : "<<(norme(u,n))<<endl;
return 0; // la signature étant int main(), tu dois renvoyer un int. Pour le main, le standard est de renvoyer un code d'erreur, 0 si OK
}

Lien vers le commentaire
Partager sur d’autres sites

Il te manque un test sur la taille de ton vecteur: la taille de ton vecteur doit être au moins supérieur à ton paramètre n.

Sinon, j'ai beaucoup de mal avec ce genre de méthode simple: un appel de méthode + une boucle for.

Alors que ton vecteur n'aura pas une dimension supérieure à 3 ou 4 :craint:.

Je te propose (et je l'ai testé) 2 choses: de l'ultra classique pour une dimension de 1, 2 ou 3. Et de l'ultra bourrin pour une dimension supérieure.

Par contre, la taille de ton exécutable risque de grossir et tes temps de compilation de s'allonger :transpi:

// inline float norme1D(vector<float> u) { return ((u.size() >= 1)? sqrt(u[1] * u[1]): 0.0f); } // <- faux
inline float norme1D(vector<float> u) { return ((u.size() >= 1)? u[0]: 0.0f); } // Merci uzak
inline float norme2D(vector<float> u) { return ((u.size() >= 2)? sqrt((u[0] * u[0]) + (u[1] * u[1])): 0.0f); }
inline float norme3D(vector<float> u) { return ((u.size() >= 3)? sqrt((u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2])): 0.0f); }

template<unsigned int N> float normeNd(vector<float> u) { return ((u.size() >= N)? ((u[N - 1] * u[N - 1]) + normeNd<N - 1>(u)): 0.0f); }
template<> float normeNd<1>(vector<float> u) { return ((u.size() >= 1)? (u[0] * u[0]): 0.0f); }
template<> float normeNd<0>(vector<float> u) { return 0.0f; }

int main( void )
{
vector<float> u;
u.push_back(2.0);
u.push_back(4.0);
u.push_back(2.0);
u.push_back(4.0);

cout << norme3D(u) << endl;
cout << sqrt( normeNd<4>(u) ) << endl;

{ // Édit
	vector<float> u;
	u.push_back(0.75f);
	u.push_back(0.5f);
	u.push_back(0.25f);

	cout << norme3D(u) << endl;
	cout << sqrt( normeNd<3>(u) ) << endl;
}

return 0;
}

Lien vers le commentaire
Partager sur d’autres sites

Ben moi je trouve que pour quelqu'un qui commence le C++, ton exemple n'est pas très bien choisi.

La syntaxe ( ? : ) est illisible quand tu commences (et après aussi, c'est useless par rapport à un if) ; les templates, faudrait déjà maîtriser les types et les retour de fonctions avant de s'y attaquer.

Introduire le mot clé inline ne sert pas des masses non plus, alors que l'optimisation est dépendante du compilo.

Et tu prones une optimisation pour 1, 2, 3, tout ça pour finir avec des appels récursifs vachement consommateurs. La récursion ici, n'est même pas intuitive, puisqu'elle s'applique sur les carrés des normes.

Et pour finir, le norme1D plante à l'exécution (il faut lire u[0]), étourderie ; et n'est pas optimisé non plus, puisque le calcul sqrt( a * a ) revient à tirer la valeur absolue de a. Tu t'épargnes des imprécisions sur le calcul flottant et du temps de calcul.

Par contre, j'aimerais bien savoir ce que tu n'aimes pas dans l'appel de méthode + boucle for ?

Lien vers le commentaire
Partager sur d’autres sites

Ben moi je trouve que pour quelqu'un qui commence le C++, ton exemple n'est pas très bien choisi.

Oui (pour les "templates" (les patrons)) et Non (pour le reste)

La syntaxe ( ? : ) est illisible quand tu commences

C'est lisible puisque condensé et je n'ai pas abusé du truc.

De plus l'opérateur ternaire tu l'apprends en même temps que les boucles, afin presque.

(et après aussi, c'est useless par rapport à un if) ;

Faux:

1) Tu peux faire un test très simple sur une seule ligne au lieu de 3-4.

2) Tu n'utilises qu'un seul "return": c'est plus facile niveau lecture au lieu d'avoir un "return" dans le "if" et un autre dans le "else".

les templates, faudrait déjà maîtriser les types et les retour de fonctions avant de s'y attaquer.

D'accord avec toi

Introduire le mot clé inline ne sert pas des masses non plus, alors que l'optimisation est dépendante du compilo.

L'optimisation est dépendante du compilateur je suis d'accord. Mais là il y a juste un "return": il va y arriver tu ne crois pas.

Mes fonctions ne sont pas énormes, justement grâce à l'opérateur ternaire

Et tu pronres une optimisation pour 1, 2, 3, tout ça pour finir avec des appels récursifs vachement consommateurs.

J'y ai pensé et je pense que c'est faux. C'est pendant la compilation que le compilateur va générer le code et je ne pense pas qu'il ait de la récursion, mais la somme des carrés complète.

Par contre, un gros défaut: tu es obligé d'utiliser les patrons avec un vrai nombre, et non pas "u.size()" par exemple.

La récursion ici, n'est même pas intuitive, puisqu'elle s'applique sur les carrés des normes.

Mais obligatoire pour faire cela avec des patrons

Et pour finir, le norme1D plante à l'exécution (il faut lire u[0]), étourderie ; et n'est pas optimisé non plus, puisque le calcul sqrt( a * a ) revient à tirer la valeur absolue de a. Tu t'épargnes des imprécisions sur le calcul flottant et du temps de calcul.

:chinois: merci et corrigé/ optimisé

Par contre, j'aimerais bien savoir ce que tu n'aimes pas dans l'appel de méthode + boucle for ?

Évidemment je n'en suis pas sûr à 100%, mais il y a de très fortes chances.

Et donc, je remplace "l'appel de méthode + boucle for" par soit le code directement soit, au pire, un appel à une fonction.

Ensuite (déjà dit), faire une boucle "For" et utiliser cette norme pour seulement un vecteur de dimension 3 ou 4, au temps aller au plus simple. (Évidemment dépend des besoins) (toujours partir de la spécialisation pour arriver, si nécessaire, à la généralisation et jamais généraliser d'entrée (enfin bon))

Enfin, si tu utilises intensivement la norme, cela va soulager un peu les temps de calcul mais perdre du temps à la compilation et de la taille exécutable. C'est un compromis.

Lien vers le commentaire
Partager sur d’autres sites

D'expérience, quand je dois lire du code que je n'ai pas fait, je préfère un if que l'opérateur ternaire. Même quand c'est moi qui l'ai fait en fait :transpi:

Après c'est sûr que t'y gagnes en ligne de codes puisque tu peux condenser 3-4 lignes en une, mais je suis pas sûr que tu y gagnes en temps/espace d'exécution, y compris sur des retour

Enfin, perso, j'utilise l'opérateur ternaire uniquement pour des affectations du type, b=(a==NULL?NULL:a->method()); et encore, je trouve ça crade quand même.

Lien vers le commentaire
Partager sur d’autres sites

Précision: le type size_t est "unsigned int" de la librairie STL.

// Version inline
inline float norme1D (vector<float> u) { return ((u.size() >= 1)? u[0]: 0.0f); }
inline float norme2D (vector<float> u) { return ((u.size() >= 2)? sqrt((u[0] * u[0]) + (u[1] * u[1])): 0.0f); }
inline float norme3D (vector<float> u) { return ((u.size() >= 3)? sqrt((u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2])): 0.0f); }
inline float norme4D (vector<float> u) { return ((u.size() >= 4)? sqrt((u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2]) + (u[3] * u[3])): 0.0f); }


// Version Template
// Test sur la taille mis dans la fonction normeNd
//template<size_t N> float sumSquare (vector<float> u) { return ((u.size() >= N)? ((u[N - 1] * u[N - 1]) + sumSquare<N - 1>(u)): 0.0f); } 
//template<> float sumSquare<1> (vector<float> u) { return ((u.size() >= 1)? (u[0] * u[0]): 0.0f); }

template<size_t N> float sumSquare (vector<float> u) { return ((u[N - 1] * u[N - 1]) + sumSquare<N - 1>(u)); }
template<> float sumSquare<1> (vector<float> u) { return (u[0] * u[0]); }
template<> float sumSquare<0> (vector<float> u) { return 0.0f; }

template<size_t N> float normeNd (vector<float> u) {  return ((u.size() >= N)? sqrt( sumSquare<N>(u) ): 0.0f); }


// Version avec ellipse
double norme (size_t size, double value, ...) {
   if (!size) return 0.0f;

   va_list list;
   double sum_square = 0.0f;

   va_start(list, size);

   do {
       value = va_arg(list, double);
       sum_square += (value * value);
   } while (--size);

   va_end(list);

   return sqrt(sum_square);
}


int main (void)
{
   vector<float> u;
   u.push_back(0.75f);
   u.push_back(0.5f);
   u.push_back(0.25f);

   cout << norme2D(u) << endl;
   cout << normeNd<2>(u) << endl;
   cout << norme(2, 0.75f, 0.5f) << endl;

   cout << norme3D(u) << endl;
   cout << normeNd<3>(u) << endl;
   cout << norme(3, 0.75f, 0.5f, 0.25f);

   return 0;
}

Lien vers le commentaire
Partager sur d’autres sites

Un petit édit: je viens de regarder le code assembleur généré (pour les fonctions "inline"), et c'est vraiment mieux de mettre des références ou des pointeurs pour le passage de paramètre de type "vector" (sinon appel du constructeur de recopie). Bon, je ne l'ai pas fait, mais c'est simple à faire et cela marche correctement :D

Sinon, il y a la version foncteur mais c'est un peu inutile pour ce cas-ci :dd:

Lien vers le commentaire
Partager sur d’autres sites

Un petit édit: je viens de regarder le code assembleur généré (pour les fonctions "inline"), et c'est vraiment mieux de mettre des références ou des pointeurs pour le passage de paramètre de type "vector" (sinon appel du constructeur de recopie). Bon, je ne l'ai pas fait, mais c'est simple à faire et cela marche correctement :D

Sinon, il y a la version foncteur mais c'est un peu inutile pour ce cas-ci :dd:

C'est sûr !, surtout sur les appels récursifs ^^

T'as oublié de tirer la valeur absolue dans Norme1D ;).

Pour ma part, j'aurais fait un itératif basique comme l'a fait NoA. Après, question de points du vue ;)

Lien vers le commentaire
Partager sur d’autres sites

C'est sûr !, surtout sur les appels récursifs ^^

Justement j'étais en train de regarder cela. Mais par défaut, il ne prend pas en compte les "inline". Mais une fois, tu mets "whole program optimisation", il n'y a plus aucun appel et donc le code (même les patrons apparemment) sont en "dur". 8)

Et là je tartine tout le monde :dd:

T'as oublié de tirer la valeur absolue dans Norme1D ;).

Effectivement

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...