Ecrire une fontion pow qui accepte un exposant réel

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjours à tous,

je suis toujours en train de coder ma bibliothèque mathématique en c++ mais (une fois de plus) j'ai un problème ou je suis bloqué et où mes recherches sont inutiles, comment écrire une fonction pow qui accepte un exposant réel ?

J'ai déjà écris ma fonction pow mais n'accepte que des exposants entiers (le code est ), j'ai un peu réfléchis a comment faire et j'ai pensé a appliqué ceci $a^n = \sqrt[\frac{1}{n}]{a}$ sauf que la fonction find_root aurait besoin de pow qui aurait besoin de find_root qui aurait besoin de pow qui aurait besoin de find_root et ceci jusqu'au stack overflow.

J'ai donc cherché une autre solution et j'ai trouvé ça $a^n = \exp(\ln(a) \times n)$ sauf que la fonction exponentielle appelle la fonction pow qui appelle la fonction exponentielle qui appelle la fonction pow et ainsi de suite jusqu'au stack overflow aussi.

Donc voici mon problème actuel, j'espère que vous pourrez m'aider à le résoudre et vous remercie d'avance. :)

Édité par LudoBike

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Staff

Cette réponse a aidé l'auteur du sujet

Salut,

Pour coder la fonction exponentielle tu n'as pas besoin de la fonction pow réelle, il te faut juste la fonction pow entière (et encore, ça c'est quand on code mal).

En effet :

$$e^x = \sum\limits_{k=0}^\infty \frac{x^k}{k!}$$

EDIT : quand $|x|<1$ la somme converge assez vite et tu peux stopper l'itération au bout de quelques $k$ (selon la précision voulue).

Ensuite tu remarque que tout nombre réel $r$ s'écrit sous la forme $n+\epsilon$ avec $n\in \mathbb{Z}$ et $|\epsilon| < 1$.

D'où $x^r = x^n\times x^\epsilon$. Tu calcules le premier terme avec pow entière et le second avec la formule que tu as donné et le développement de la fonction exponentielle.

Édité par Algue-Rythme

+0 -0

EDIT : quand $|x|<1$ la somme converge assez vite et tu peux stopper l'itération au bout de quelques $k$ (selon la précision voulue).

Algue-Rythme

(* à prononcer sous la forme d'une petite chanson style pom-pom girl *)

Le calcul de convergence en fonction du x et du type flottant d'entrée.

First : Always RTFM - "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein

+0 -0
Auteur du sujet

Donc exp s'écrit comme ça

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
template<typename T>
std::enable_if_t<std::is_floating_point<T>{}, T>
    exp(T const x)
{
    T k;
    T x_pow_k = 1, fact_k = 1;
    T to_return = 0;

    for (k = 0; k < 10; k++; x_pow_k *= x; fact_k *= k)
    {
    to_return += x_pow_k/fact_k;
    }

    return to_return;
}

et pow comme ça

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
template<typename T>
std::enable_if_t<std::is_arithmetic<T>{}, T>
    pow(T const base, T const exponent)
{
    T const decimal_of_exp = math::fmod(exponent, 1);

    if (exponent == 0)
    return base;
    else if (decimal_of_exp != 0)
    return math::pow(base, exponent - decimal_of_exp) * math::exp(math::ln(base)*decimal_of_exp);
    else if (exponent < 0)
    return 1/math::pow(base, math::abs(exponent));
    else
    return base * math::pow(base, exponent - 1);
}

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0

J'ai une question qui est partiellement liée. Comment on fait pour calculer $ln(x)$ ? Je sais qu'on peut faire des développements (limités) mais, en l'occurence, on parle toujours de celui de Taylor pour $ln(1 + x)$ qui a un rayon de convergence de 1 ! Comment on fait pour les valeurs supérieures ? On utilise les propriétés du logarithme $log(x*y) = log(x) + log(y)$ ? Ou plus simplement, le développement de $ln(1 + x)$ converge-t-il à droite (Pour $x > 0$), mais j'ai le souvenir que ce n'est pas le cas ?

+1 -0
Auteur du sujet

C'est ok pour exp() à par le nombre maximal accepté pour ne pas dépasser les limites des types réels.

Sinon j'ai la même question que Gawaboumga, comment on calcule le logarithme népérien ?

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Staff

Salut,

Juste une idée comme ça. C'est surement pas optimisé du tout, mais ça peut fournir des résultats corrects.

Tu cherches à résoudre $e^n=x, n \in \mathbb{Z}$ avec $x$ le nombre pour lequel tu cherches $\ln{x}$.

Pour cela tu procèdes par dichotomie sur les valeurs possibles de $n$, qui ne doivent pas excéder quelques centaines, et tu calcules chaque puissance entière par exponentiation rapide. Tu cherches la valeur de $n$ pour la quelle $e^n$ est le plus proche de $x$ (par valeur supérieure).

Alors comme $x=e^n\times y$ alors $\ln{(x)}=\ln{(e^n\times y)}=\ln{(e^n)}+ \ln{(y)}=n+\ln{(y)}$ avec $y < 1$ par définition de $n$.

Édité par Algue-Rythme

+1 -0
Auteur du sujet

Salut,

juste une question en rapport avec le projet, j'ai voulu essayer mon code mais la compil de mon code de test m'a envoyé plein de référence indéfinie dans la bibliothèque. Du coup j'ai décidé de ne plus séparer la déclaration et la définition de mes templates. J'ai fais tous les changement mais je me demande juste où je met les fichiers .hpp qui contienne mes templates (dans src ou dans include) ?

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Auteur du sujet

Tu mets tes heades dans include. Et pour le fait de ne pas séparer les définitions, c'est juste normal.

Ksass`Peuk

Ok je l'ai fait mais par contre j'ai un problème avec ln.hpp qui dit ‘pow’ is not a member of ‘math’ alors que j'ai include pow.hpp dans le fichier. (pour les details c'est sur github)

Édité par LudoBike

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Auteur du sujet

Donc il faut que je fasse ça

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
namespace math
{

    template<typename T>
    std::enable_if_t<std::is_arithmetic<T>{}, T>
        pow(T const base, T const exp);

}

#include "pow.hpp"

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Auteur du sujet

Merci pour les références indéfinis, le problème est résolue par contre ma fonction pow me renvoie une erreur qui dit que si on l'appelle avec un unsigned int sa ne marche pas car il ne peut appeler ln<unsigned int>(base) sauf que un int a une valeur décimal toujours nulle, du coup j'ai essayé de l'expliciter comme ça

1
2
 else if (std::is_floating_point<T>::value && decimal_of_exp != 0)
            return math::pow<T>(base, exp - decimal_of_exp) * math::exp<T>(math::ln<T>(base)*decimal_of_exp);

mais ça me renvoye toujours la même erreur donc est-ce qu'il y a une solution, j'ai pensé a faire une fonction pow pour les entiers et une pour les réels.

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Auteur du sujet

j'ai pensé a faire une fonction pow pour les entiers et une pour les réels

En terme de conception et d'efficacité algorithmique, ce serait une bonne chose.

Algue-Rythme

Ok je vais faire ça :)

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Auteur du sujet

Bon maintenant mon code de test compile mais fait un segmentation fault que je ne comprent absolument pas, ddd me dit

1
2
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401040 in math::fmod<float> (numer=<error reading variable: Cannot access memory at address 0x7fffff7feffc>, denom=<error reading variable: Cannot access memory at address 0x7fffff7feff8>) at /home/ludovic/workspace/C++/Math-library/test/../include/libmath/fmod.hpp:34

Si vous avez une idée de où sa peut venir je suis preneur :)

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte