Frage

Seltsame Dinge passieren, wenn ich versuche, die Kubikwurzel einer Zahl zu finden.

Der folgende Code gibt mir nicht definiert. In cmd:. -1 # IND

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

Während dies ein völlig in Ordnung funktioniert. In cmd: 4,93242414866094

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

Von mathematisch es funktionieren muss, da wir die Kubikwurzel aus einer negativen Zahl haben können. Pow ist von Visual C ++ 2010 math.h Bibliothek. Irgendwelche Ideen?

War es hilfreich?

Lösung

pow(x, y) von <cmath> funktioniert nicht, wenn x negativ ist, und y ist nicht integral.

Dies ist eine Einschränkung von std::pow, wie in dem C-Standard dokumentiert und auf cppreference :

  

Fehlerbehandlung

     
      
  • Fehler gemeldet werden, wie in math_errhandling angegeben
  •   
  • Wenn Basis endlich ist und negative und exp endlich und nicht-ganze Zahl ist, eine Domäne Fehler auftritt und ein Entfernungsfehler auftreten können.
  •   
  • Wenn Basis Null und exp Null ist, ein Domain-Fehler auftreten können.
  •   
  • Wenn Basis Null und exp negativ ist, ein Domain-Fehler oder ein Pol Fehler auftreten können.
  •   

Es gibt ein paar Möglichkeiten, um diese Einschränkung:

  • Cube-Verwurzelung ist das gleiche wie etwas zur 1/3 Macht zu übernehmen, so dass Sie std::pow(x, 1/3.) tun könnten.

  • In C ++ 11, können Sie std::cbrt . C ++ 11 eingeführt sowohl Quadratwurzel und Kubikwurzelfunktionen, aber keine allgemeine n-te Wurzel-Funktion, die die Grenzen der std::pow windet.

Andere Tipps

Die Macht 1/3 ist ein Sonderfall. Im Allgemeinen nicht-ganzzahligen Potenzen von negativen Zahlen sind komplex. Es wäre nicht sinnvoll sein, für pow für besondere Fälle wie integer Wurzeln zu überprüfen, und außerdem 1/3 als doppelt so hoch ist nicht genau 1/3!

Ich weiß nicht, über die Visual C ++ pow, aber mein Mann sagt Seite unter Fehler:

  

EDOM Das Argument x negativ und y ist kein integraler Wert. Dies würde zu einer komplexen Zahl zur Folge hat.

Sie werden eine spezialisierte Kubikwurzel-Funktion verwenden müssen, wenn Sie Kubikwurzeln von negativen Zahlen wollen -. Oder geschnittene Ecken und Absolutwert nehmen, dann Kubikwurzel nehmen, dann multiplizieren die Zeichen wieder auf

Beachten Sie, dass je nach Kontext, eine negative Zahl x auf die 1/3 Leistung ist nicht unbedingt die negative Kubikwurzel Sie erwarten. Es könnte genauso gut die erste komplexe Wurzel, x^(1/3) * e^(pi*i/3) sein. Dies ist die Konvention Mathematica verwendet; es ist auch vernünftig nur zu sagen, es ist nicht definiert.

Während (-1) ^ 3 = -1, kann man einfach nicht eine rationale Macht einer negativen Zahl nehmen und eine wirkliche Antwort erwarten. Dies liegt daran, es gibt auch andere Lösungen für diesen rationalen Exponenten, die in der Natur imaginär sind.
http: / /www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0

ähnlich, Grundstück x ^ x. Für x = -1/3, sollte diese eine Lösung. Allerdings ist diese Funktion in R erachtet undefined für x <0

Daher erwarten nicht math.h Magie zu tun, dass es ineffizient machen würde, nur die sich Zeichen ändern.

Erraten Sie die negativen nehmen Gotta aus und legen es in danach. Sie können eine haben Wrapper für Sie tun, wenn Sie wirklich wollen.

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

Do nicht zu double abgegebenen (double) verwenden, eine doppelte numerische Konstante statt:

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

sollte es tun!

Auch: nicht enthalten <math.h> in C ++ Projekte, aber die Verwendung <cmath> statt

.

Alternativ Verwendung pow aus dem <complex> Header für die von buddha genannten Gründe

pow( x, y ) ist das gleiche wie (das heißt äquivalent) exp( y * log( x ) )

Wenn log (x) ist ungültig dann pow (x, y) auch.

Ebenso können Sie keine 0 an die Macht der alles, obwohl mathematisch sollte 0 sein.

C ++ 11 hat die cbrt Funktion (siehe zum Beispiel http: // en.cppreference.com/w/cpp/numeric/math/cbrt ), so dass Sie so etwas wie

schreiben
#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;
}

Ich habe keinen Zugriff auf die C ++ Standard, damit ich weiß nicht, wie das negative Argument behandelt wird ... einen Test auf ideone http://ideone.com/bFlXYs scheint zu bestätigen, dass C ++ (gcc-4.8.1) mit dieser Regel cbrt(x)=-cbrt(-x) wenn x<0 die Kubikwurzel erstreckt; für diese Erweiterung können Sie sehen http://mathworld.wolfram.com/CubeRoot.html

Ich war für cubit Wurzel suchen und diesen Thread gefunden, und es fällt mir ein, dass der folgende Code könnte funktionieren:

#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;
}

Ich denke, man sollte nicht zu verwechseln Potenzierung mit der n-ten Wurzel einer Zahl. Sehen Sie sich die gute alte Wikipedia

, da die 1/3 immer 0 zurück, da sie als ganze Zahl betrachtet werden ... versuchen, mit 1.0 / 3.0 ... es ist das, was ich denke, aber versuchen und implementieren ... und vergessen Sie nicht, Variablen zu deklarieren, die 1,0 und 3,0 als Doppel ...

Hier ist eine kleine Funktion, die ich oben geklopft.

#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;
}

Es verwendet Newton-Raphson eine Kubikwurzel zu finden.

Einige Zeit Newton -Raphson klemmt, wenn die Wurzel auf 0 sehr nahe ist dann das Derivat erhalten groß und es schwingen kann. Also ich habe es geklemmt und gezwungen, neu zu starten, wenn das passiert. Wenn Sie mehr Genauigkeit benötigen, können Sie die FLT_EPSILONs ändern.

Wenn Sie überhaupt keine Mathematik-Bibliothek haben Sie auf diese Weise können die kubische Wurzel berechnen:

Kubikwurzel

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;
}

Es ist ergibt sich aus der sqrt Algorithmus unten. Die Idee ist, dass b und x / b / b größer und kleiner von der kubischen Wurzel x. Also, der Mittelwert beider liegt näher an der kubischen Wurzel x.

Quadratwurzel und Kubikwurzel (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

Im Gegensatz zur Quadratwurzel, last_b_1 und last_b_2 sind in der kubischen Wurzel erforderlich, da b flimmert. Sie können diese Algorithmen modifizieren, um die vierte Wurzel, fünfte Wurzel zu berechnen und so weiter.

Dank meines Mathelehrer Herr Brenner in der 11. Klasse, die diesen Algorithmus hatte mir gesagt, für sqrt.

Performance

Ich habe es getestet auf einem Arduino mit 16MHz Taktfrequenz:

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top