Ecrire une fontion pow qui accepte un exposant réel

a marqué ce sujet comme résolu.

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. :)

+0 -0

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.

+0 -0

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);
}
+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 ?

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$.

+1 -0

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) ?

+0 -0

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)

+0 -0

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"
+0 -0

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.

+0 -0

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 :)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

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