Bibliotheque fonctionnelle : opérations, composition d'objets fonctions

Soyez le premier à donner votre avis sur cette source.

Vue 4 725 fois - Téléchargée 171 fois

Description

Extension de la STL (http://www.cplusplus.com/reference/std/functional/) avec mes conventions de nommage, cette petite bibliothèque permet la définition de fonctions sous forme de classe.

Il peut être pratique de pouvoir définir des fonctions "objets", c'est-à-dire des objets dont l'opérateur '()' est défini, et qui possède des attributs et des méthodes comme tout objet. Comme cela vous pouvez définir des méthodes "setAccuracy" ou "setPrecision", "setCoefficients", "setKnotVector", etc. Utilisée sans abus, elle peut vous donner un code plus concis à l'utilisation des fonctions définies à partir de ces templates.

Cette bibliothèque inclus les opérateurs + - * / et % (composition à ne pas confondre avec le modulo classique), permettant de pouvoir appeler les fonctions sous la forme (f + g)(x) par exemple.

Source / Exemple :


#include "Function.h"
#include "Integral.h"
#include <iostream>

/* Exemple d'utilisation des fonctions sous forme d'objet */

/* Définition des fonctions de type R -> R */
typedef std::unary_function<double, double> RealFunction;

/* Une simple fonction x² */
class SquareFunction : public RealFunction
{
public:
	double operator () ( double x ) const { return x*x; }
};

/* Une fonction polynôme */
class PolynomFunction : public RealFunction
{
public:
	PolynomFunction( double * coeffs, int degree ) : _coeffs( coeffs ), _degree( degree ) {}
	double operator () ( double x ) const
	{
		double y = 0.0, xn = 1.0;
		int i;

		for ( i = _degree; i >= 0; i-- )
		{
			y += _coeffs[ i ] * xn;
			xn *= x;
		}
		return y;
	}
protected:
	double * _coeffs;
	int _degree;
};

/* Une classe vecteur (qui n'est pas une fonction) */
class Vector3
{
public:
	Vector3( double x, double y, double z ) : _x( x ), _y( y ), _z( z ) {}
	double length() const { return sqrt( _x * _x + _y * _y + _z * _z ); }
private:
	double _x, _y, _z;
};

/* Une classe hélice */
class Helix3 : public std::unary_function<double, Vector3>
{
public:
	Vector3 operator () ( double t ) const { return Vector3( cos( t ), sin( t ), t ); }
	// Vecteur tangent
	Vector3 derivative( double t ) const { return Vector3( -sin( t ), cos( t ), 1. ); }
};

int main(int argc, char **argv)
{
	using std::cout;
	using std::endl;

	// x²
	double coeffs1[] = { 1, 0, 0 };
	PolynomFunction polynom1( coeffs1, 2 );

	// 2x + 1
	double coeffs2[] = { 2, 1 };
	PolynomFunction polynom2( coeffs2, 1 );

	// L'opérateur '%' est défini comme l'opérateur de composition.
	// Ceci revient à calculer (2x + 1)²
	cout << "Calcul de (2x + 1)² avec x = 3 : " << ( polynom1 % polynom2 )( 3. ) << endl;

	// Utilisation de la méthode adaptive de l'intégration de Simpson.
	SimpsonIntegral<PolynomFunction> integral( polynom1 );
	cout << "Intégrale de x² sur [0,1] : " << integral( 0., 1. ) << endl;

	// Utilisation d'un adaptateur pour les intégrales de fonctions plus complexes.
	cout << "Intégrale de x² + 2x + 1 sur [0,1] : " << simpson_integral( polynom1 + polynom2 )( 0., 1. ) << endl;

	// Composition avec appel de la méthode &Vector3::length :
	//
	// std::mem_fun_ref( &Vector3::length ) crée un objet fonction pointant sur la méthode Vector3::length.
	//
	// Helix3 : R -> R^3
	// Vector3::length : R^3 -> R
	// h : R -> R
	//
	// avec h(x) = Vector3::length( Helix3( x ) )
	cout << "Distance de l'hélice à l'origine à t = pi : " << ( std::mem_fun_ref( &Vector3::length ) % Helix3() )( M_PI ) << endl;

	// Calcul de la longueur parcourue sur une courbe :
	//
	// Pour composer des fonctions, nous devons s'assurer qu'elles sont unaires.
	// Dans le cas contraire, nous devons fixer un des arguments.
	// std::bind1st( f( x, y ), c ) est équivalent à g( y ) = f( c, y ) avec x = c fixé.
	//
	// Helix3::derivative est considérée comme une fonction binaire (accepte '*this' et un réel t).
	//
	// Ici nous calculons l'intégrale de la norme du vecteur tangent de la courbe.
	cout << "Longueur parcourue sur une hélice pour t dans [0,pi] : " <<
		simpson_integral(
			std::mem_fun_ref( &Vector3::length ) % std::bind1st( std::mem_fun_ref( &Helix3::derivative ), Helix3() )
		) ( 0., M_PI ) << endl;
	return 0;
}

Conclusion :


Sur le même modèle il est tout à fait possible de définir les opérateurs && || etc. pour étendre cette librairie. Ou bien définir les opérateurs (fonction + réel)(x), (fonction * réel)(x), (en n'oubliant pas la commutativité).

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cptpingu
Messages postés
3801
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
15 novembre 2019
90 -
Je parlais de faire des .hxx, regarde mes sources, j'utilise ce genre de procédé (donc .cc, .hh et .hxx ou .cpp, .hpp, .hxx).
Dans ton cas, vu que la plupart des classes sont très concises, ce n'est pas nécessaire (je l'aurais peut être fait juste pour "SimpsonIntegral", mais c'est franchement pour pinailler :p).

(10 pour la propreté, c'est cette qualité là qui doit être montré à des débutants).
ordiman85
Messages postés
41
Date d'inscription
samedi 4 mars 2006
Statut
Membre
Dernière intervention
19 mars 2010
-
Merci pour ces remarques. Et merci pour le conseil du "using namespace", désormais je ne serai plus un abuseur de cette atrocité ! Etant très attaché à la propreté du code, si tu as d'autres conseils, je suis preneur !

"Essaie de séparer le code de sa définition"
Je suppose que tu parles de séparer les déclarations et l'implémentation, malheureusement je n'ai pas trouvé de solution, puisque mes structures sont des templates.

PS : je viens de modifier la source, avec pas mal de modifs dont le mot 'bibliothèque' ;)
cptpingu
Messages postés
3801
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
15 novembre 2019
90 -
C'est propre, commenté en Doxygen, et le code est élégant. C'est du bon travail.

Quelques petites remarques:
- Library se traduit par bibliothèque et non librairie (bookstore en anglais). Ça pique un peu aux yeux, c'est dommage.
- Évite les "using namespace", voir: http://0217021.free.fr/portfolio/axel.berardino/articles/bon-usage-using-namespace
- Essaie de séparer le code de sa définition, avec des .hxx. Néanmoins, comme ton code est concis, je comprends que tu n'es pas fait la séparation. J'aurais sûrement fait pareil.

C'est rare d'avoir du code intéressant, et celui-ci en fait partie.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.