найти корень куба в C ++? - PullRequest
       1

найти корень куба в C ++?

10 голосов
/ 24 ноября 2010

Странные вещи случаются, когда я пытаюсь найти корень куба числа.

Следующий код возвращает меня неопределенным. В cmd: -1. # IND

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

Хотя этот работает отлично. В cmd: 4.93242414866094

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

С математической точки зрения это должно работать, поскольку мы можем получить корень куба из отрицательного числа. Pow из библиотеки Visual C ++ 2010 math.h. Есть идеи?

Ответы [ 12 ]

15 голосов
/ 24 ноября 2010

pow(x, y) из <cmath> НЕ работает, если x отрицателен, а y не целочислен.

Это ограничение std::pow, как указано в стандарте C и на cppreference :

Обработка ошибок

  • Об ошибках сообщается, как указано в math_errhandling
  • Если основание конечное и отрицательное, а exp конечное и нецелое, возникает ошибка домена и может возникать ошибка диапазона.
  • Если base равно нулю, а exp равно нулю, может возникнуть ошибка домена.
  • Если основание равно нулю, а exp отрицательно, может возникнуть ошибка домена или ошибка полюса.

Существует несколько способов обойти это ограничение:

  • Корень куба - это то же самое, что взять что-то в 1/3 степени, так что вы можете сделать std::pow(x, 1/3.).

  • В C ++ 11 вы можете использовать std::cbrt. В C ++ 11 введены функции как квадратного, так и кубического корней, но нет общей n-й корневой функции, которая преодолевает ограничения std::pow.

8 голосов
/ 24 ноября 2010

Мощность 1/3 - это особый случай. В общем случае нецелые степени отрицательных чисел являются сложными. Для pow было бы непрактично проверять особые случаи, такие как целочисленные корни, и, кроме того, 1/3 как двойное не совсем 1/3!

Я не знаю, что такое визуальный язык C ++, но моя справочная страница говорит об ошибках:

EDOM Аргумент x отрицателен, а y не является целочисленным значением. Это приведет к комплексному числу.

Вам нужно будет использовать более специализированную функцию корня куба, если вы хотите, чтобы корни куба имели отрицательные числа - или вырезать углы и принять абсолютное значение, затем взять корень куба и затем умножить знак обратно.

Обратите внимание, что в зависимости от контекста отрицательное число x в степени 1/3 не обязательно является ожидаемым отрицательным корнем куба. С таким же успехом это может быть первый сложный корень, x^(1/3) * e^(pi*i/3). Это соглашение Mathematica использует; также разумно просто сказать, что оно не определено.

7 голосов
/ 24 ноября 2010

Хотя (-1) ^ 3 = -1, вы не можете просто взять рациональную степень отрицательного числа и ожидать реального ответа. Это потому, что существуют другие решения этого рационального показателя, которые являются мнимыми по своей природе.
http://www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0

Аналогично, сюжет х ^ х. Для х = -1/3 это должно иметь решение. Однако эта функция считается неопределенной в R для x <0. </p>

Поэтому не ожидайте, что math.h будет творить магию, которая сделает его неэффективной, просто измените знаки самостоятельно.

3 голосов
/ 24 ноября 2010

Полагаю, тебе нужно вынуть негатив и вставить его потом. Вы можете сделать это для вас, если вы действительно этого хотите.

function yourPow(double x, double y)
{
    if (x < 0)
        return -1.0 * pow(-1.0*x, y);
    else
        return pow(x, y);
}
2 голосов
/ 09 сентября 2013

C ++ 11 имеет функцию cbrt (см., Например, http://en.cppreference.com/w/cpp/numeric/math/cbrt), чтобы вы могли написать что-то вроде

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

У меня нет доступа к стандарту C ++, поэтому я делаюне знаю, как обрабатывается отрицательный аргумент ... тест на ideone http://ideone.com/bFlXYs, кажется, подтверждает, что C ++ (gcc-4.8.1) расширяет корень куба с этим правилом cbrt(x)=-cbrt(-x) когда x<0; для этогорасширение вы можете увидеть http://mathworld.wolfram.com/CubeRoot.html

2 голосов
/ 24 ноября 2010

pow( x, y ) соответствует (то есть эквивалентно) exp( y * log( x ) )

, если log (x) недопустим, то pow (x, y) также.

Аналогично, вы не можетевыполнить 0 до степени чего-либо, хотя математически это должно быть 0.

2 голосов
/ 24 ноября 2010

Не приводите к double с помощью (double), вместо этого используйте двойную числовую константу:

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

Должен сделать свое дело!

Также: не включайте <math.h> в проекты C ++, но вместо этого используйте <cmath>.

В качестве альтернативы используйте pow из заголовка <complex> по причинам, указанным buddhabrot

1 голос
/ 04 мая 2012

Я искал cubit root и нашел этот поток, и мне пришло в голову, что следующий код может работать:

#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;
}
0 голосов
/ 02 февраля 2015

Если у вас когда-либо нет математической библиотеки, вы можете использовать этот способ для вычисления кубического корня:

кубического корня

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

Он получен из алгоритма sqrt ниже.Идея состоит в том, что b и x / b / b больше и меньше от кубического корня x.Таким образом, среднее значение обоих значений находится ближе к кубическому корню из x.

Квадратный корень и Кубический корень (в 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

В отличие от квадратного корня, last_b_1 и last_b_2 требуются в кубическом корне, потому что мигает b.Вы можете изменить эти алгоритмы для вычисления четвертого корня, пятого корня и т. Д.

Благодаря моему учителю математики г-ну Бреннеру в 11-м классе, который рассказал мне этот алгоритм для sqrt.

производительности

Я тестировал его на Arduino с тактовой частотой 16 МГц:

0 голосов
/ 26 февраля 2014

Вот небольшая функция, которую я выбил.

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

Он использует Ньютона-Рафсона для поиска корня куба.

Иногда Ньютон-Рафсон застревает, если корень очень близокдо 0, тогда производная может стать большой, и она может колебаться.Поэтому я зажал и заставил его перезапустить, если это произойдет.Если вам нужна большая точность, вы можете изменить FLT_EPSILONs.

...