Pergunta

Coisas estranhas acontecem quando tento encontrar a raiz cúbica de um número.

O código a seguir me retorna indefinido.Em cmd:-1.#IND

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

Embora este funcione perfeitamente bem.Em cmd:4.93242414866094

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

Do ponto de vista matemático, deve funcionar, pois podemos obter a raiz cúbica de um número negativo.Pow é da biblioteca math.h do Visual C++ 2010.Alguma ideia?

Foi útil?

Solução

pow(x, y) a partir de <cmath> não funciona se X for negativo e Y não integral.

Esta é uma limitação de std::pow, conforme documentado no padrão C e em CPPPREFERÊNCIA:

Manipulação de erros

  • Os erros são relatados conforme especificado em Math_errhandling
  • Se a base for finita e negativa e o exp for é finito e não inteiro, ocorre um erro de domínio e um erro de intervalo pode ocorrer.
  • Se a base for zero e o exp for zero, poderá ocorrer um erro de domínio.
  • Se a base for zero e o EXP for negativo, pode ocorrer um erro de domínio ou um erro de pólo.

Existem algumas maneiras de contornar essa limitação:

  • Rooting de cubo é o mesmo que levar algo para o poder de 1/3, para que você possa fazer std::pow(x, 1/3.).

  • Em C ++ 11, você pode usar std::cbrt. C ++ 11 introduziu funções de raiz quadrada e raízes cubos, mas nenhuma função raiz genérica que supera as limitações de std::pow.

Outras dicas

O poder 1/3 é um caso especial. Em geral, os poderes não integrais de números negativos são complexos. Não seria prático para o Pow verificar se há casos especiais como raízes inteiras e, além disso, 1/3 Como duplo não é exatamente 1/3!

Não sei sobre o Visual C ++ Pow, mas minha página do meu homem diz em erros:

EDOM O argumento x é negativo e y não é um valor integral. Isso resultaria em um número complexo.

Você precisará usar uma função raiz de cubo mais especializada se desejar raízes de cubo de números negativos - ou cortar cantos e assumir o valor absoluto, depois pegue a raiz do cubo e multiplique a sinal novamente.

Observe que, dependendo do contexto, um número negativo x para o 1/3 O poder não é necessariamente a raiz negativa do cubo que você está esperando. Poderia ser facilmente a primeira raiz complexa, x^(1/3) * e^(pi*i/3). Esta é a convenção que Mathematica usa; Também é razoável apenas dizer que é indefinido.

Enquanto (-1)^3 = -1, você não pode simplesmente tomar um poder racional de um número negativo e esperar uma resposta real. Isso ocorre porque existem outras soluções para esse expoente racional de natureza imaginária.
http://www.wolframalpha.com/input/?i=x^(1/3),+x+From+-5+To+0

Da mesma forma, plot x^x. Para x = -1/3, isso deve ter uma solução. No entanto, essa função é considerada indefinida em r para x <0.

Portanto, não espere que o Math.h faça mágica que o tornaria ineficiente, basta mudar os sinais.

Acho que você precisa tirar o negativo e colocá -lo depois. Você pode fazer com que um invólucro faça isso por você, se realmente quiser.

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

Não escalada para double usando (double), use uma constante numérica dupla: em vez disso:

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

Deve fazer o truque!

Além disso: não inclua <math.h> em projetos C ++, mas use <cmath> em vez de.

Alternativamente, use pow de <complex> Cabeçalho pelas razões declaradas por Buddhabrot

pow( x, y ) é o mesmo que (ou seja, equivalente a) exp( y * log( x ) )

Se o log (x) for inválido, o pow (x, y) também é.

Da mesma forma, você não pode executar 0 ao poder de nada, embora matematicamente deva ser 0.

C ++ 11 tem o cbrt função (veja por exemplo http://en.cppreference.com/w/cpp/numeric/math/cbrt) para que você possa escrever algo como

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

Eu não tenho acesso ao padrão C ++, então não sei como o argumento negativo é tratado ... um teste em ideone http://ideone.com/bflxys parece confirmar que C ++ (GCC-4.8.1) estende a raiz do cubo com esta regra cbrt(x)=-cbrt(-x) quando x<0; Para esta extensão, você pode ver http://mathworld.wolfram.com/cubeoot.html

Eu estava procurando por raízes de cúbitos e encontrei esse tópico e me ocorre que o código a seguir poderia funcionar:

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

Eu acho que você não deve confundir a exponenciação com a raiz NTH de um número. Veja o bom velho Wikipedia

porque 1/3 sempre retornará 0 pois será considerado um número inteiro ...tente com 1.0/3.0...é o que penso, mas tento implementar...e não esqueça de declarar variáveis ​​contendo 1.0 e 3.0 como double...

Aqui está uma pequena função que eu bata.

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

Ele usa Newton-Raphson para encontrar uma raiz de cubo.

Em algum momento, Newton -Raphson fica preso, se a raiz estiver muito próxima de 0, o derivado pode ficar grande e pode oscilar. Então, eu prendi e forcei a reiniciar se isso acontecer. Se você precisar de mais precisão, poderá alterar os FLT_EPSILONS.

Se você não possui biblioteca de matemática, pode usar desta maneira para calcular a raiz cúbica:

raiz cúbica

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

Deriva do sqrt Algoritmo abaixo. A ideia é que b e x / b / b maior e menor da raiz cúbica de x. Então, a média de ambos está mais próxima da raiz cúbica de x.

Raiz quadrada e raiz cúbica (em 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

Em contraste com a raiz quadrada, last_b_1 e last_b_2 são necessários na raiz cúbica porque B oscilantes. Você pode modificar esses algoritmos para calcular a quarta raiz, a quinta raiz e assim por diante.

Obrigado ao meu professor de matemática, Herr Brenner, na 11ª série, que me contou este algoritmo para sqrt.

atuação

Eu o testei em um Arduino com frequência de relógio de 16MHz:

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top