59 votes

Opérations physiques sécurisées en C++

Est-ce que cela a un sens en C++ de définir les unités physiques comme des types séparés et de définir des opérations valides entre ces types ?

Y a-t-il un avantage à introduire un grand nombre de types et de surcharges d'opérateurs au lieu d'utiliser simplement des valeurs à virgule flottante pour les représenter ?

Exemple :

class Time{...};
class Length{...};
class Speed{...};
...
Time operator""_s(long double val){...}
Length operator""_m(long double val){...}
...
Speed operator/(const Length&, const Time&){...}

Time , Length y Speed ne peut être créé que comme type de retour de différents opérateurs ?

17 votes

Cela se fait généralement au moment de la compilation avec des modèles. Voir boost.units par exemple.

2 votes

Voir aussi Métaprogrammation de modèles C++ : Concepts, outils et techniques de Boost et au-delà par David Abrahams et Aleksey Gurtovoy - il traite de l'analyse dimensionnelle en temps réel dans le domaine de l'informatique. 3.1 .

0 votes

Voici un bon article qui traite de cette question exacte avec du code : R. Cmelik, N. Gehani, "Dimensional Analysis with C++," IEEE Software, Volume 5 Issue 3, May 1988, Page 21-27. Désolé, je n'ai pas le PDF pour vous.

56voto

Mike Seymour Points 130519

Est-ce que cela a un sens en C++ de définir les unités physiques comme des types séparés et de définir des opérations valides entre ces types ?

Absolument. La bibliothèque standard de Chrono le fait déjà pour les points de temps et les durées.

Y a-t-il un avantage à introduire un grand nombre de types et de surcharges d'opérateurs au lieu d'utiliser simplement des valeurs à virgule flottante pour les représenter ?

Oui : vous pouvez utiliser le système de types pour détecter les erreurs telles que l'ajout d'une masse à une distance au moment de la compilation, sans ajouter de surcharge au moment de l'exécution.

Si vous n'avez pas envie de définir les types et les opérateurs vous-même, Boost dispose d'une fonction Bibliothèque des unités pour ça.

0 votes

Également pour éviter les surcharges sans fin boost::operator est utile en dérivant automatiquement les surcharges basées sur le CRTP.

4 votes

Correction mineure : vous devriez utiliser boost::units (ou similaire) "si vous n'avez pas envie de définir les types et les opérateurs vous-même", comme vous l'avez déclaré, o si vous êtes un programmeur qui ne souffre pas de Le syndrome "Pas inventé ici" et réalise la futilité de réinventer la roue . Donc, en gros, oui, utilisez-le.

22voto

Viktor Sehr Points 5634

Je recommande vraiment boost::unités pour ça. Il fait toute la conversion à la compilation et vous donne également une erreur de compilation si vous essayez d'utiliser des dimensions erronées. exemple de code psuedo :

length l1, l2, l3;
area a1 = l1 * l2; // Compiles
area a2 = l1 * l2 * l3; // Compile time error, an area can't be the product of three lengths.
volume v1 = l1 * l2 * l3; // Compiles

13voto

Dave Points 10916

J'ai suivi cette voie. Les avantages sont tous les nombreux et bons avantages normaux de la sécurité de type. Les inconvénients que j'ai rencontrés :

  • Vous voudrez enregistrer les valeurs intermédiaires dans les calculs... comme les secondes au carré. Avoir ces valeurs type est quelque peu dénuée de sens (secondes^2 n'est évidemment pas un type comme velocity est).
  • Vous voudrez effectuer des calculs de plus en plus complexes qui nécessiteront de plus en plus de surcharges/définitions d'opérateurs.

En fin de compte, il est extrêmement propre pour des calculs simples et des objectifs simples. Mais lorsque les mathématiques se compliquent, il est difficile de faire jouer un système d'unités typées.

7 votes

Utilisation de auto pour les intermédiaires résout ce problème :)

4 votes

Des constantes comme l'accélération m/s^2 est en fait des mètres par seconde par seconde, et non des mètres par seconde au carré. Je ne suis pas non plus d'accord avec le fait qu'une constante contenant une seconde au carré n'aurait aucun sens. Si c'est ce que sont les unités pour cette constante, alors stockez-les de cette façon. Si vous faites un problème de physique, vous devriez certainement écrire le résultat intermédiaire sur votre page de cette façon, même si cela n'a pas de sens en soi.

0 votes

La partie "plus de surcharges" est trompeuse. Il n'existe que 7 unités SI fondamentales, et toutes les autres sont des puissances rationnelles de ces 7 unités. Cela signifie qu'il n'y a pas besoin d'une seule surcharge ; operator* il suffit d'ajouter les 7 puissances rationnelles des deux arguments.

10voto

Tout le monde a mentionné les garanties de sécurité des types comme un plus. Un autre ENORME avantage est la possibilité d'abstraire le concept (longueur) des unités (mètre).

Ainsi, par exemple, un problème courant en matière d'unités est de mélanger le système SI et le système métrique. Lorsque les concepts sont abstraits sous forme de classes, ce problème n'existe plus :

Length width = Length::fromMeters(2.0);
Length height = Length::fromFeet(6.5);
Area area = width * height; //Area is computed correctly!
cout << "The total area is " << area.toInches() << " inches squared.";

L'utilisateur de la classe n'a pas besoin de savoir quelles unités la représentation interne utilise... du moins, tant qu'il n'y a pas de graves problèmes d'arrondi.


J'aimerais vraiment que plus de bibliothèques de trigonométrie fassent cela avec les angles, parce que je dois toujours chercher s'ils attendent des degrés ou des radians...

0 votes

"abstraire le concept (longueur) des unités (mètre)." Vous savez, bien que un peu comme semble utile, mais il semble aussi qu'il viole le principe KISS.

8 votes

@SigTerm : Ce n'est pas vrai du tout ! En fait, c'est exactement le contraire : les utilisateurs de votre classe n'ont plus besoin de se préoccuper des détails de mise en œuvre tels que " pieds " ou " pouces ", et peuvent se concentrer sur des concepts plus larges tels que " distance " ou " angle ". C'est le site Un exemple classique de la manière dont la POO est la plus utile !

0 votes

(opinion) Je suppose que c'est une question de goût. La plupart des pays utilisent le système métrique et je ne m'attendrais pas à ce que quelque chose en rapport avec la physique utilise des pieds et des livres au lieu de mètres et de kilogrammes. Votre approche est logique pour une sorte de base de données de stockage de matériaux (réels), la comptabilité ( ?), les boutiques en ligne, les calculateurs de frais de port et d'autres applications similaires. Pour ces applications, il est logique d'utiliser des quantités qui peuvent être converties en différentes unités. Mais pour les calculs de physique, cela ne semble pas être une fonctionnalité très utile.

1voto

Fred Mitchell Points 1068

Oui, c'est logique. Pas seulement en physique, mais dans n'importe quelle discipline. En finance, par exemple, les taux d'intérêt sont exprimés en unités d'intervalles de temps inverses (généralement exprimés par an). L'argent a de nombreuses unités différentes. La conversion entre elles ne peut se faire qu'avec un taux croisé, a dimensions d'une monnaie divisée par une autre. Les paiements d'intérêts, de dividendes, de capital, etc. ont généralement lieu à une certaine fréquence.

Il peut empêcher de multiplier deux valeurs et de se retrouver avec une valeur illégale. Il peut empêcher d'additionner des dollars et des euros, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X