trovando radice cubica in C ++?
Domanda
Strane cose accadono quando si tenta di trovare la radice cubica di un numero.
I seguenti restituisce il codice di me undefined. In cmd:. -1 # IND
cout<<pow(( double )(20.0*(-3.2) + 30.0),( double )1/3)
Anche se questo funziona perfettamente bene. In cmd: 4,93242414866094
cout<<pow(( double )(20.0*4.5 + 30.0),( double )1/3)
Da modo matematico deve funzionare dal momento che siamo in grado di avere la radice cubica di un numero negativo. Pow è da C 2010 biblioteca math.h visiva ++. Tutte le idee?
Soluzione
pow(x, y)
da <cmath>
non funziona se x è negativo ey non integrale.
Questa è una limitazione di std::pow
, come documentato nello standard C e cppreference :
La gestione degli errori
- Gli errori vengono segnalati come specificato nella math_errhandling
- Se la base è finito e negativo e exp è finito e non intero, si verifica un errore di dominio e può verificarsi un errore di campo.
- Se la base è pari a zero e exp è pari a zero, potrebbe verificarsi un errore di dominio.
- Se la base è zero e exp è negativa, un errore di dominio oppure potrebbe verificarsi un errore di polo.
Ci sono un paio di modi per aggirare questa limitazione:
-
Cube-radicamento è lo stesso di prendere qualcosa al potere 1/3, in modo che si possa fare
std::pow(x, 1/3.)
. -
In C ++ 11, è possibile utilizzare
std::cbrt
. C ++ 11 illustra sia funzioni cubo-radice radice quadrata e, ma non-esima n funzione radice generica che supera i limiti distd::pow
.
Altri suggerimenti
Il 1/3
potere è un caso speciale. In generale, i poteri non integranti di numeri negativi sono complesse. Non sarebbe pratico per pow per verificare la presenza di casi particolari come radici intere, e inoltre, 1/3
come una doppia non è esattamente 1/3!
Non so circa il C ++ visivo pow, ma la mia pagina uomo dice sotto gli errori:
EDOM
Ilx
argomento è negativo ey
non è un valore integrale. Ciò si tradurrebbe in un numero complesso.
Si dovrà utilizzare una funzione radice cubica più specializzati, se si desidera radici cubiche di numeri negativi -. O angoli tagliati e prendere valore assoluto, quindi prendere radice cubica, poi moltiplicare il segno indietro
Si noti che a seconda del contesto, un numero negativo x
alla potenza 1/3
non è necessariamente la radice cubica negativo vi aspettate. Potrebbe essere benissimo la prima radice complesso, x^(1/3) * e^(pi*i/3)
. Questo è usi convenzione Mathematica; è anche ragionevole dire solo che è indefinito.
Mentre (-1) ^ 3 = -1, non si può semplicemente prendere un potere razionale di un numero negativo e si aspettano una risposta reale. Questo è perché ci sono altre soluzioni a questo esponente razionale che sono immaginari in natura.
http: / /www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0
Similmente, la trama x ^ x. Per x = -1/3, questo dovrebbe avere una soluzione. Tuttavia, questa funzione si considera undefined in R per x <0.
Quindi, non aspettatevi math.h fare magia che renderebbe inefficiente, basta cambiare i segni stessi.
Indovinate devi prendere il negativo fuori e metterlo in seguito. Si può avere un wrapper fare questo per voi, se si vuole veramente.
function yourPow(double x, double y)
{
if (x < 0)
return -1.0 * pow(-1.0*x, y);
else
return pow(x, y);
}
Do not cast double
utilizzando (double)
, utilizzare una costante numerica doppia invece:
double thingToCubeRoot = -20.*3.2+30;
cout<< thingToCubeRoot/fabs(thingToCubeRoot) * pow( fabs(thingToCubeRoot), 1./3. );
dovrebbe fare il trucco!
Inoltre: non comprendono <math.h>
in progetti C ++, ma l'uso <cmath>
invece
In alternativa, l'uso pow
dal collettore <complex>
per i motivi indicati dalla buddhabrot
pow( x, y )
è lo stesso (cioè equivalente a) exp( y * log( x ) )
se log (x) non è valida pow allora (x, y) è anche.
Allo stesso modo non è possibile eseguire 0 al potere di qualsiasi cosa, anche se matematicamente dovrebbe essere 0.
C ++ 11 ha la funzione cbrt
(vedi ad esempio http: // en.cppreference.com/w/cpp/numeric/math/cbrt ) in modo da poter scrivere qualcosa di simile
#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;
}
Non ho accesso al C ++ standard in modo da non so come l'argomento negativo è gestita ... un test su Ideone http://ideone.com/bFlXYs sembra confermare che C ++ (gcc-4.8.1) estende la radice cubica con questa regola quando cbrt(x)=-cbrt(-x)
x<0
; per questa estensione è possibile vedere http://mathworld.wolfram.com/CubeRoot.html
ero alla ricerca di radici cubito e ha trovato questa discussione e mi viene in mente che il seguente codice potrebbe funzionare:
#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;
}
Credo che non si dovrebbe confondere elevamento a potenza con l'ennesima radice di un numero. Vedere il buon vecchio Wikipedia
perché il terzo sarà sempre ritornare 0 in quanto sarà considerato come intero ... provare con 1.0 / 3.0 ... è quello che penso ma cerco di implementare ... e non dimenticate di dichiarare le variabili che contengono 1.0 e 3.0 come doppio ...
Ecco una piccola funzione Ho bussato su.
#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;
}
Si utilizza Newton-Raphson per trovare una radice cubica.
Qualche Newton -Raphson si blocca, se la radice è molto vicino a 0 allora il barattolo derivato ottenere grande e può oscillare. Così ho Strinsi e costretto a riavviare se ciò accade. Se avete bisogno di più la precisione è possibile modificare le FLT_EPSILONs.
Se avete mai avuto alcun libreria matematica è possibile utilizzare in questo modo per calcolare la radice cubica:
radice cubica
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;
}
E 'deriva dalla algoritmo di sqrt
di seguito. L'idea è che b
e x / b / b
grande e più piccola dalla radice cubica di x
. Così, la media dei due si trova più vicino alla radice cubica di x
.
Radice quadrata e radice cubica (in 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
In contrasto con la radice quadrata, last_b_1
e last_b_2
sono richiesti nella radice cubica perché b sfarfallio. È possibile modificare questi algoritmi per calcolare la radice quarta, quinta radice e così via.
Grazie al mio insegnante di matematica Herr Brenner nel 11 ° grado che mi ha detto questo algoritmo per sqrt
.
Prestazioni
ho testato su un Arduino con frequenza di clock 16 MHz: