Вычисление кубического корня для отрицательного числа - программирование
Подтвердить что ты не робот

Вычисление кубического корня для отрицательного числа

Итак, чтобы быть коротким,

3 √ (-8) = (-8) 1/3

console.log(Math.pow(-8,1/3));
//Should be -2

Но когда я его тестирую, он выводит

NaN

Почему? Это ошибка, или, как ожидается, это будет в первую очередь? Я использую JavaScript для рисования графиков, но это испортит график.

4b9b3361

Ответ 1

Вы можете использовать этот фрагмент, чтобы вычислить его. Он также работает для других полномочий, например. 1/4, 1/5 и т.д.

function nthroot(x, n) {
  try {
    var negate = n % 2 == 1 && x < 0;
    if(negate)
      x = -x;
    var possible = Math.pow(x, 1 / n);
    n = Math.pow(possible, n);
    if(Math.abs(x - n) < 1 && (x > 0 == n > 0))
      return negate ? -possible : possible;
  } catch(e){}
}

nthroot(-8, 3);

Источник: http://gotochriswest.com/blog/2011/05/06/cube-root-an-beyond/

Более быстрый подход для простого вычисления кубического корня:

Math.cbrt = function(x) {
    var sign = x === 0 ? 0 : x > 0 ? 1 : -1;

    return sign * Math.pow(Math.abs(x), 1 / 3);
}

Math.cbrt(-8);

Обновление

Чтобы найти кубический корень с целым числом, вы можете использовать следующую функцию, вдохновленную этим ответом:

// positive-only cubic root approximation
function cbrt(n)
{
    var a = n; // note: this is a non optimized assumption

    while (a * a * a > n) {
        a = Math.floor((2 * a + (n / (a * a))) / 3);
    }

    return a;
}

Оно начинается с предположения, что сходится к ближайшему целому числу a, для которого a^3 <= n. Эта функция может быть отрегулирована таким же образом, чтобы поддерживать отрицательную базу.

Ответ 2

Нет ошибок; вы поднимаете отрицательное число до дробной мощности; следовательно, NaN.

Топ-хит Google для этого - от Dr Math объяснение довольно хорошее. Он говорит, что для действительных чисел (не комплексных чисел в любом случае) отрицательное число, поднятое до дробной мощности, может не быть реальным числом. Простейшим примером является, вероятно,

-4 ^ (1/2)

который по существу вычисляет квадратный корень из -4. Несмотря на то, что кубический корень -8 действительно имеет реальные решения, я думаю, что большинство программных библиотек считают более эффективным не выполнять всю сложную арифметику и возвращать NaN только тогда, когда мнимая часть отлична от нуля, и в противном случае даст вам хороший реальный ответ.

ИЗМЕНИТЬ

Просто для того, чтобы абсолютно ясно, что NaN - это ожидаемый результат, см. официальную спецификацию ECMAScript 5.1, раздел 15.8.2.13. В нем говорится:

Если x < 0 и x конечны и y конечен и y не является целым числом, то результат равен NaN.

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

Пожалуйста, не думайте, что JavaScript - единственный такой язык. С++ делает то же самое:

Если x является конечным отрицательным, а y конечным, но не целочисленным значением, оно вызывает ошибку домена.

Ответ 3

Две ключевые проблемы:

  • Математически существует несколько кубических корней отрицательного числа: -2, но также и 2 комплексных корня (см. кубические корни единства).
  • Объект Javascript Math (и большинство других стандартных математических библиотек) не будет выполнять дробную степень отрицательных чисел. Он преобразует дробную мощность в поплавок до того, как функция получит его, поэтому вы просите функцию вычислить силу с плавающей запятой отрицательного числа, которое может иметь или не иметь реального решения. Таким образом, он делает прагматичную вещь и отказывается пытаться вычислить такую ​​ценность.

Если вы хотите получить правильный ответ, вам нужно будет решить, как правильно вы будете математически корректны, и напишите эти правила в нестандартную реализацию pow.

Все функции библиотеки ограничены, чтобы избежать чрезмерного времени вычислений и ненужной сложности.

Ответ 4

Мне нравятся другие ответы, но как насчет переопределения Math.pow, чтобы он мог работать со всеми n-ыми корнями отрицательных чисел:

//keep the original method for proxying
Math.pow_ = Math.pow;

//redefine the method
Math.pow = function(_base, _exponent) {
  if (_base < 0) {
    if (Math.abs(_exponent) < 1) {
      //we're calculating nth root of _base, where n === 1/_exponent
      if (1 / _exponent % 2 === 0) {
        //nth root of a negative number is imaginary when n is even, we could return
        //a string like "123i" but this would completely mess up further computation
        return NaN;
      }/*else if (1 / _exponent % 2 !== 0)*/
      //nth root of a negative number when n is odd
      return -Math.pow_(Math.abs(_base), _exponent);
    }
  }/*else if (_base >=0)*/
  //run the original method, nothing will go wrong
  return Math.pow_(_base, _exponent);
};

Спрятанный с некоторыми тестовыми примерами, дайте мне крик, если вы заметили ошибку!

Ответ 5

Итак, я вижу кучу методов, которые вращаются вокруг Math.pow(...), что классно, но на основе формулировки щедрости я предлагаю несколько иной подход.

Существует несколько вычислительных аппроксимаций для решения корней, некоторые из которых принимают более быстрые шаги, чем другие. В конечном счете точка остановки сводится к желаемой степени точности (это действительно зависит от вас/проблема, которая решается).

Я не буду объяснять математику в мельчайших подробностях, но следующие реализации кубических корневых аппроксимаций, которые прошли целевой тест (тест на бонус - также добавил отрицательный диапазон, из-за вопроса заглавие). Каждая итерация в цикле (см. Петли while(Math.abs(xi-xi0)>precision) в каждом методе) приближается к желаемой точности. Как только точность достигнута, формат применяется к числу так, чтобы он был точным, как вычисление, полученное из итерации.

var precision = 0.0000000000001;
function test_cuberoot_fn(fn) { 
    var tested = 0, 
    failed = 0; 
    for (var i = -100; i < 100; i++) { 
        var root = fn(i*i*i); 
        if (i !== root) { 
            console.log(i, root); 
            failed++; 
        } 
        tested++; 
    } 
    if (failed) { 
        console.log("failed %d / %d", failed, tested); 
    }else{
        console.log("Passed test");
    }
}
test_cuberoot_fn(newtonMethod);
test_cuberoot_fn(halleysMethod);

Внедрение Ньютона

function newtonMethod(cube){
    if(cube == 0){//only John Skeet and Chuck Norris
        return 0; //can divide by zero, we'll have
    }             //to settle for check and return
    var xi = 1;
    var xi0 = -1;
    while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
        xi0=xi;
        xi = (1/3)*((cube/(xi*xi))+2*xi);
    }
    return Number(xi.toPrecision(12));
}

Выполнение галльной аппроксимации note. Галлейное приближение принимает более быстрые меры для решения куба, поэтому оно вычисляется быстрее, чем аппроксимация Ньютона.

function halleysMethod(cube){
    if(cube == 0){//only John Skeet and Chuck Norris
        return 0; //can divide by zero, we'll have
    }             //to settle for check and return
    var xi = 1;
    var xi0 = -1;
    while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
        xi0=xi;
        xi = xi*((xi*xi*xi + 2*cube)/(2*xi*xi*xi+cube));
    }
    return Number(xi.toPrecision(12));
}

Ответ 6

Работает в консоли Chrome

function cubeRoot(number) {
    var num = number;
    var temp = 1;
    var inverse = 1 / 3;
    if (num < 0) {
        num = -num;
        temp = -1;
    }
    var res = Math.pow(num, inverse);
    var acc = res - Math.floor(res);
    if (acc <= 0.00001)
        res = Math.floor(res);
    else if (acc >= 0.99999)
        res = Math.ceil(res);
    return (temp * res);
}

cubeRoot(-64) // -4
cubeRoot(64)  //  4

Ответ 7

//не являются кубическими корнями отрицательных чисел, такими же, как положительные, кроме знака?

Math.cubeRoot= function(n, r){
    var sign= (n<0)? -1: 1;
    return sign*Math.pow(Math.abs(n), 1/3);
}
Math.cubeRoot(-8)

/*  returned value: (Number)
-2
*/

Ответ 8

Как глава, в ES6 теперь есть функция Math.cbrt.

В моем тестировании в Google Chrome он работает почти в два раза быстрее, чем Math.pow. Интересно, что мне пришлось добавить результаты, иначе хром сделал бы лучшую работу по оптимизации функции pow.

//do a performance test on the cube root function from es6
var start=0, end=0, k=0;
start = performance.now();
k=0;
for (var i=0.0; i<10000000.0; i+=1.0)
{
    var j = Math.cbrt(i);
    //k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
    var j = Math.pow(i,0.33333333);
    //k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
    var j = Math.cbrt(i);
    k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
    var j = Math.pow(i,0.33333333);
    k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);

Результат:

cbrt took:468.28200000163633 0
pow took:77.21999999921536 0
cbrt took:546.8039999977918 1615825909.5248165
pow took:869.1149999940535 1615825826.7510242

Ответ 9

Просто хочу подчеркнуть, что в ES6 существует функция native кубический корневой. Таким образом, вы можете просто сделать это (проверьте поддержку здесь)

Math.cbrt(-8) вернет вас -2