trouver racine cubique en C ++?
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?
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 destd::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
Lex
argument est négatif ety
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: