Question

Des choses étranges se produisent lorsque je tente de trouver la racine cubique d'un nombre.

Les retours de code suivant me défini. Cmd:. -1 #IND

cout<<pow(( double )(20.0*(-3.2) + 30.0),( double )1/3)

Alors que celui-ci fonctionne parfaitement bien. Cmd: 4,93242414866094

cout<<pow(( double )(20.0*4.5 + 30.0),( double )1/3)

De façon mathématique, il doit travailler, puisque nous pouvons avoir la racine cubique d'un nombre négatif. Pow est de Visual C ++ 2010 bibliothèque math.h. Toutes les idées?

Était-ce utile?

La solution

pow(x, y) de <cmath> ne fonctionne pas si x est négatif et y est non entier.

Ceci est une limitation de std::pow, comme indiqué dans la norme C et sur cppreference :

  

Traitement des erreurs

     
      
  • Les erreurs sont signalées comme indiqué dans math_errhandling
  •   
  • Si la base est finie et négative et exp est fini et non entier, une erreur de domaine se produit et une erreur d'intervalle peut se produire.
  •   
  • Si la base est égale à zéro et exp est égal à zéro, une erreur de domaine peut se produire.
  •   
  • Si la base est égale à zéro et exp est négatif, une erreur de domaine ou d'une erreur de pôle peut se produire.
  •   

Il y a deux manières autour de cette limitation:

  • Cube déracinement est la même chose que prendre quelque chose à la puissance 1/3, vous pouvez donc faire std::pow(x, 1/3.).

  • En C ++ 11, vous pouvez utiliser std::cbrt . C ++ 11 introduit à la fois racine carrée et les fonctions de cube racine, mais pas n-ième fonction racine générique qui surmonte les limitations de std::pow.

Autres conseils

Le 1/3 de puissance est un cas particulier. En général, les pouvoirs non intégrantes des nombres négatifs sont complexes. Il ne serait pas pratique pour les pow pour vérifier des cas particuliers comme les racines entières, et d'ailleurs, 1/3 comme un double est pas exactement un tiers!

Je ne sais pas sur le Visual C ++ pow, mais ma page man sous erreurs:

  

EDOM Le x argument est négatif et y est pas une valeur entière. Cela se traduirait par un nombre complexe.

Vous devrez utiliser un cube plus spécialisé fonction racine si vous voulez des racines cubiques de nombres négatifs -. Ou coins coupés et prendre valeur absolue, puis prendre racine cubique, puis multipliez le dos de signe sur

Notez que selon le contexte, un certain nombre de négatif x à la puissance 1/3 est pas nécessairement la racine cubique négatif que vous vous attendez. Il pourrait tout aussi bien être la première racine complexe, x^(1/3) * e^(pi*i/3). Ceci est l'utilisation de Mathematica convention; il est également raisonnable de dire simplement qu'il est défini.

Alors que (-1) ^ 3 = -1, vous ne pouvez pas simplement prendre une puissance rationnelle d'un nombre négatif et attendre une réponse réelle. En effet, il existe d'autres solutions à cet exposant rationnel qui sont imaginaires dans la nature.
http: / /www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0

Similairement, terrain x ^ x. Pour x = -1/3, cela devrait avoir une solution. Cependant, cette fonction est réputée non définie dans R pour x <0

Par conséquent, ne vous attendez pas à faire de la magie math.h qui rendrait inefficace, il suffit de changer les signes vous.

Je suppose que tu dois prendre le négatif et de le mettre dans la suite. Vous pouvez avoir un wrapper faire pour vous si vous voulez vraiment.

function yourPow(double x, double y)
{
    if (x < 0)
        return -1.0 * pow(-1.0*x, y);
    else
        return pow(x, y);
}

Ne pas jeter à double en utilisant (double), utilisez une constante à double numérique à la place:

double thingToCubeRoot = -20.*3.2+30;
cout<< thingToCubeRoot/fabs(thingToCubeRoot) * pow( fabs(thingToCubeRoot), 1./3. );

devrait faire l'affaire!

En outre: ne pas inclure <math.h> dans les projets de C, mais l'utilisation <cmath> à la place

.

Vous pouvez également utiliser pow de l'en-tête de <complex> pour les raisons exposées par buddhabrot

pow( x, y ) est le même que (à savoir l'équivalent de) exp( y * log( x ) )

si log (x) est invalide, pow (x, y) est également.

De même, vous ne pouvez pas effectuer 0 à la puissance de quoi que ce soit, bien que mathématiquement il devrait être 0.

C ++ 11 a la fonction de cbrt (voir par exemple http: // en.cppreference.com/w/cpp/numeric/math/cbrt ) de sorte que vous pouvez écrire quelque chose comme

#include <iostream>
#include <cmath>

int main(int argc, char* argv[])
{
   const double arg = 20.0*(-3.2) + 30.0;
   std::cout << cbrt(arg) << "\n";
   std::cout << cbrt(-arg) << "\n";
   return 0;
}

Je n'ai pas accès à la norme C ++, donc je ne sais pas comment l'argument négatif est traité ... un test sur ideone http://ideone.com/bFlXYs semble confirmer que C ++ (gcc-4.8.1) étend la racine cubique avec cette règle cbrt(x)=-cbrt(-x) quand x<0; pour cette extension, vous pouvez voir http://mathworld.wolfram.com/CubeRoot.html

Je cherchais racine et trouvé ce cubit fil et il me vient que le code suivant pourrait fonctionner:

#include <cmath>
using namespace std;

function double nth-root(double x, double n){
    if (!(n%2) || x<0){
        throw FAILEXCEPTION(); // even root from negative is fail
    }

    bool sign = (x >= 0);

    x = exp(log(abs(x))/n);

    return sign ? x : -x;
}

Je pense que vous ne devriez pas confondre exponentiation avec le nième racine d'un nombre. Voir le bon vieux Wikipedia

parce que le 1/3 vaudra toujours 0 car il sera considéré comme entier ... essayez avec 1.0 / 3.0 ... il est ce que je pense, mais essayer de mettre en œuvre ... et ne pas oublier de déclarer des variables contenant comme doubles 1,0 et 3,0 ...

Voici une petite fonction I en cloque.

#define uniform() (rand()/(1.0 + RAND_MAX))

double CBRT(double Z)
{
    double guess = Z;
    double x, dx;
    int loopbreaker;

retry:
    x = guess * guess * guess;
    loopbreaker = 0;
    while (fabs(x - Z) > FLT_EPSILON)
    {
        dx = 3 * guess*guess;
        loopbreaker++;
        if (fabs(dx) < DBL_EPSILON || loopbreaker > 53)
        {
            guess += uniform() * 2 - 1.0;
            goto retry;
        }
        guess -= (x - Z) / dx;
        x = guess*guess*guess;
    }

    return guess;
}

Il utilise Newton-Raphson pour trouver une racine cubique.

Quelque temps Newton -Raphson est bloqué, si la racine est très proche de 0, la boîte dérivé obtenir grand et il peut osciller. J'ai donc serré et forcé à redémarrer si cela se produit. Si vous avez besoin d'une plus grande précision, vous pouvez modifier les FLT_EPSILONs.

Si vous avez toujours pas de bibliothèque de mathématiques, vous pouvez utiliser cette façon de calculer la racine cubique:

racine cubique

double curt(double x) {
  if (x == 0) {
    // would otherwise return something like 4.257959840008151e-109
    return 0;
  }
  double b = 1; // use any value except 0
  double last_b_1 = 0;
  double last_b_2 = 0;
  while (last_b_1 != b && last_b_2 != b) {
    last_b_1 = b;
    // use (2 * b + x / b / b) / 3 for small numbers, as suggested by  willywonka_dailyblah
    b = (b + x / b / b) / 2;
    last_b_2 = b;
    // use (2 * b + x / b / b) / 3 for small numbers, as suggested by  willywonka_dailyblah
    b = (b + x / b / b) / 2;
  }
  return b;
}

Il est dérive de l'algorithme de sqrt ci-dessous. L'idée est que b et x / b / b plus grand et plus petit de la racine cubique de x. Ainsi, la moyenne des deux est plus proche de la racine cubique de x.

Racine carrée et cubique Racine (en Python)

def sqrt_2(a):
    if a == 0:
        return 0
    b = 1
    last_b = 0
    while last_b != b:
        last_b = b
        b = (b + a / b) / 2
    return b

def curt_2(a):
    if a == 0:
        return 0
    b = a
    last_b_1 = 0;
    last_b_2 = 0;
    while (last_b_1 != b and last_b_2 != b):
        last_b_1 = b;
        b = (b + a / b / b) / 2;
        last_b_2 = b;
        b = (b + a / b / b) / 2;
    return b

Contrairement à la racine carrée, last_b_1 et last_b_2 sont nécessaires à la racine cubique parce que b vacille. Vous pouvez modifier ces algorithmes pour calculer la racine quatrième, cinquième racine et ainsi de suite.

Merci à mon professeur de mathématiques M. Brenner à la 11e année qui m'a dit cet algorithme pour sqrt.

Performance

Je l'ai testé sur un Arduino avec une fréquence d'horloge de 16 MHz:

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top