Les dérivés de C/C++?
J'ai quelques expressions telles que x^2+y^2
que je voudrais utiliser pour certains calculs mathématiques. Une des choses que j'aime faire, c'est de prendre des dérivées partielles de la expressions.
Donc si f(x,y) = x^2 + y^2
puis la partielle de f
à l'égard de x
serait 2x
, l'partielle à l'égard de y
serait 2y
.
J'ai écrit une dinky fonction à l'aide d'une des différences finies la méthode, mais je suis en cours d'exécution dans des tas de problèmes avec précision en virgule flottante. Par exemple, je me retrouve avec 1.99234
au lieu de 2
. Existe-il des bibliothèques qui prennent en charge symbolique de la différenciation? Toutes les autres suggestions?
- Rouler votre propre serait une mauvaise idée. J'ai pris un croisé grad cours de calcul formel, et les choses ne sont pas encore tout à fait complète. Simpliste différenciation pourrait être fait par l'application de maty règles et ensuite essayer de remplacer et d'évaluer... difficile de le faire en C/C++.
- Voir aussi stackoverflow.com/questions/627055/... et peut-être la balise de votre question dérivés
Vous devez vous connecter pour publier un commentaire.
J'ai mis en place de telles bibliothèques dans plusieurs langues différentes, mais malheureusement pas C. Si vous traitez uniquement avec des polynômes (sommes, produits, les variables, les constantes et les pouvoirs), il est assez facile. Fonctions trigonométriques sont aussi pas trop mal. Rien de plus compliqué et vous aurez probablement être mieux de prendre le temps de maîtriser quelqu'un d'autre bibliothèque.
Si vous décidez de rouler, j'ai quelques suggestions pour vous simplifier la vie:
Utilisation immuable des structures de données (purement fonctionnelle des structures de données pour représenter des expressions.
Utilisation Hans Boehm garbage collector pour gérer la mémoire pour vous.
Pour représenter une somme linéaire, l'utilisation d'un fini de la carte (par exemple, un arbre de recherche binaire) à la carte de chaque variable à son coefficient.
Si vous êtes prêt à intégrer Lua dans votre code C et faites vos calculs, j'ai mis mon code Lua à http://www.cs.tufts.edu/~nr/drop/lua. L'une des fonctionnalités les plus agréables, c'est qu'il peut prendre une expression symbolique, de les différencier, et de compiler les résultats en Lua. Vous pourrez bien sûr trouver aucune documentation n'importe quoi 🙁
Arriver numérique de la différenciation "droit" (dans le sens de minimiser les erreurs) peut être très difficile. Pour commencer, vous voudrez peut-être prendre un coup d'oeil à la Numerical Recipies section sur numérique dérivés.
Gratuitement symbolique paquets de math, vous devriez regarder GiNaC. Vous pouvez aussi consulter SymPy, autonome, pur python symbolique paquet de maths. Vous trouverez que SymPy est beaucoup plus facile à explorer, car vous pouvez l'utiliser de manière interactive à partir du Python en ligne de commande.
La fin, les deux Mathematica et Maple, C Api. Vous avez besoin d'une installation/de la version sous licence du programme à utiliser les bibliothèques, mais les deux peuvent facilement faire le type de différentiation symbolique que vous êtes après.
Si vous faites numérique de la différenciation ("évaluer la dérivée de f(x) à x = x0") et vous savez que vous êtes équations à l'avance (c'est à dire, pas la saisie de l'utilisateur), alors je vous recommande de FADBAD++. C'est un C++ bibliothèque de modèles pour la résolution numérique des instruments dérivés à l'aide de La différentiation automatique. C'est très rapide, et précis.
Vous pouvez améliorer la précision du numérique, de la différenciation de deux façons simples
Utiliser un petit delta. Vous semblez avoir utilisé une valeur de près de
1e-2
. Commencez avec1e-8
, et de tester si la plus petite fait du mal ou de l'aide. Évidemment, vous ne pouvez pas obtenir trop près de la machine de précision sur1e-16
pour le double.Utiliser centrale différences plutôt que vers l'avant (ou l'arrière), les différences.
c'est à dire
df_dx =(f(x+delta) - f(x-delta)) /(2.0*delta)
Pour des raisons de l'annulation de la hausse de la troncature termes, l'erreur dans la centrale des différences d'estimation est de l'ordre
delta^2
plutôt que le delta de l'avant des différences. Voir http://en.wikipedia.org/wiki/Finite_differenceSi c'est vraiment le genre de fonction que vous souhaitez utiliser, il serait assez facile d'écrire une bibliothèque de classe. Commencez avec un seul Terme, avec un coefficient et un exposant. Ont un Polynôme qui serait constitué d'un ensemble de Termes.
Si vous définissez une interface pour les méthodes mathématiques d'intérêt (par exemple, add/sub/mul/div/différencier/intégration), vous êtes à la recherche à un GoF Composite modèle. À la fois le Terme et le Polynôme serait à implémenter cette interface. Le Polynôme serait tout simplement de faire une itération sur chaque Terme dans sa Collection.
Il serait certainement plus facile de tirer parti d'un package existant plutôt que d'en écrire votre propre, mais si vous êtes déterminé à écrire votre propre, et vous êtes prêt à passer un peu de temps à l'apprentissage de certains coins sombres de C++, vous pouvez utiliser le Coup de pouce.Proto de Boost pour concevoir votre propre bibliothèque.
De Coeur, Coup De Pouce.Proto permet de convertir les valide en C++ d'expression, telles que
x * x + y * y
à un l'expression du modèle - essentiellement une représentation de l'arbre d'analyse de cette expression à l'aide de imbriquéestruct
s -- et ensuite effectuer n'importe quel calcul de plus que l'arbre d'analyse à une date ultérieure en appelantproto::eval()
sur elle. Par défaut,proto::eval()
est utilisé pour évaluer l'arbre comme s'il avait été exécuté directement, mais il n'ya aucune raison pourquoi vous ne pouvez pas modifier le comportement de chaque fonction ou à l'opérateur de prendre une symbolique dérivés à la place.Bien que ce serait un extrêmement complexe solution à votre problème, il pourrait néanmoins être beaucoup plus facile que d'essayer de rouler votre propre expression des modèles à l'aide de C++ template techniques de métaprogrammation.
x * x + y * y
en tapant simplement que C++ expression textuellement dans votre code, si vous avez écrit le code pour manipuler des ASTs (par exemple, pour l'évaluation, la compilation, l'impression ou (pour les expressions mathématiques) différenciation/intégration/extension/simplification, vous pouvez ensuite l'appliquer. ...Désolé d'avoir ce jusqu'au bout de 6 ans. Cependant, j'ai été à la recherche pour une bibliothèque de mon projet et j'ai vu @eduffy suggère FADBAD++. J'ai lu la documentation et revint à votre question. Je sens que ma réponse sera bénéfique, par conséquent, le code suivant est à votre cas.
La sortie est
Un autre exemple, disons que nous nous sommes intéressés à la dérivée première de
sin()
. Analytiquement, il estcos
. C'est génial parce que nous avons besoin de comparer la vraie dérivée d'une fonction donnée et ses numérique de contrepartie pour calculer l'erreur vraie.Le résultat est
J'ai créé une bibliothèque en C++, vous pouvez voir l'exemple ici:
https://github.com/MartinKosicky/auto_diff/blob/master/sample/main.cpp
L'utilisation est assez simple, il prend également en charge les matrices. Je l'ai utilisé pour créer Réseau de Neurones Récurrent... j'aurais besoin d'ajouter des GPU de la multiplication de matrice si
C'est le genre d'un côté car il s'applique à Lisp et pas de C/C++, mais il peut aider d'autres personnes à la recherche pour des tâches similaires ou vous pourriez obtenir quelques idées sur la mise en œuvre de quelque chose de similaire en C/C++ sur votre propre. SICP a quelques conférences sur le sujet pour lisp:
En Lisp, c'est assez simple (et dans d'autres langages fonctionnels, avec un puissant filtrage et de types polymorphes). En C, vous aurait probablement fortement d'utiliser les énumérations et les structures pour obtenir la même puissance (pour ne pas mentionner d'allocation/libération de la mémoire). On pourrait définitivement code ce dont vous avez besoin en ocaml, en moins d'une heure --je dirais que la vitesse de frappe est le facteur limitant. Si vous avez besoin de C, vous pouvez réellement appeler ocaml à partir de C (et vice versa).
Pour calculer uniquement la première commande de produits dérivés est assez trivial à mettre en œuvre.
Mais c'est un art pour le faire rapidement.
Vous avez besoin d'une classe, qui contient
Vous serait alors écrire les opérateurs d'addition et de soustraction et ainsi de suite et, comme les fonctions sin() qui mettent en œuvre la base et bien connu des règles pour cette opération.
Pour calculer ordre supérieur dérivés doivent être effectuées en utilisant tronquée de la série de taylor.
Vous pouvez également demander mentionnés ci-dessus classe à elle-même, le type de la valeur et de produits dérivés valeurs devrait être un argument de modèle.
Mais ce moyen de calcul et de stockage de produits dérivés plus d'une fois.
tronquée de la série de taylor, il y a deux bibliothèques disponibles pour cela:
http://code.google.com/p/libtaylor/
http://www.foelsche.com/ctaylor
Ont un coup d'oeil à Théano, il prend en charge différentiation symbolique (dans le contexte de réseaux de Neurones). Le projet est open source si donc vous devriez être en mesure de voir comment ils le font.