12

数値の立方根を見つけようとすると、奇妙なことが起こります。

次のコードは未定義を返します。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 ライブラリからのものです。何か案は?

4

12 に答える 12

17

pow(x, y)<cmath>x が負で y が非整数の場合、 fromは機能しません。

std::powC 標準およびcppreferenceで文書化されているように、これは の制限です。

エラー処理

  • エラーは math_errhandling で指定されたとおりに報告されます
  • base が有限かつ負で、exp が有限で非整数の場合、定義域エラーが発生し、範囲エラーが発生する可能性があります。
  • base が 0 で exp が 0 の場合、定義域エラーが発生する可能性があります。
  • base がゼロで exp が負の場合、ドメイン エラーまたは極エラーが発生する可能性があります。

この制限を回避するには、いくつかの方法があります。

  • 立方根は、何かを 1/3 乗することと同じなので、std::pow(x, 1/3.).

  • C++11 では、 を使用できますstd::cbrt。C++11 では、平方根関数と立方根関数の両方が導入されましたが、 の制限を克服する一般的な n 乗根関数は導入されていませんstd::pow

于 2010-11-24T16:32:52.623 に答える
8

電源1/3は特殊なケースです。一般に、負の数の非整数ベキは複素数です。pow が整数根のような特殊なケースをチェックするのは現実的で1/3はありません。

視覚的な C++ pow についてはわかりませんが、私のマニュアル ページにはエラーの下に次のように書かれています。

EDOM引数xが負でyあり、整数値ではありません。これは複素数になります。

負の数の立方根が必要な場合は、より特殊な立方根関数を使用する必要があります。または、コーナーをカットして絶対値を取得し、次に立方根を取得してから、符号を掛け直します。

コンテキストによっては、負の数x1/3累乗が必ずしも期待する負の立方根であるとは限らないことに注意してください。それは簡単に最初の複雑な根であるx^(1/3) * e^(pi*i/3). これは mathematica が使用する規則です.未定義であると言うのも合理的です。

于 2010-11-24T16:36:13.897 に答える
7

(-1)^3 = -1 ですが、単純に負の数の有理数をとって実際の応答を期待することはできません。これは、この有理指数には本質的に虚数である別の解があるためです。
http://www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0

同様に、x^x をプロットします。x = -1/3 の場合、これには解があるはずです。ただし、この関数は x < 0 の場合、R では未定義と見なされます。

したがって、 math.h が非効率になる魔法を期待しないでください。自分で符号を変更してください。

于 2010-11-24T16:35:34.287 に答える
3

ネガを取り出して、後で挿入する必要があると思います。本当に必要な場合は、ラッパーにこれを実行させることができます。

function yourPow(double x, double y)
{
    if (x < 0)
        return -1.0 * pow(-1.0*x, y);
    else
        return pow(x, y);
}
于 2010-11-24T16:35:11.313 に答える
2

pow( x, y )と同じです(つまり、同等です)exp( y * log( x ) )

log(x) が無効な場合、pow(x,y) も無効です。

同様に、数学的には 0 であるべきですが、0 の累乗を実行することはできません。

于 2010-11-24T16:52:30.173 に答える
2

doubleを使用してにキャストしないでください(double)。代わりに double の数値定数を使用してください。

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

トリックを行う必要があります!

<math.h>また、C++ プロジェクトには含めないでください<cmath>。代わりに使用してください。

または、 buddhabrot が述べた理由powでヘッダーから使用します<complex>

于 2010-11-24T16:34:30.823 に答える
1

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;
}
于 2012-05-04T00:13:28.187 に答える
0

1/3は整数と見なされるため、常に0を返すため... 1.0 / 3.0で試してください...それは私が思うことですが、実装してみてください...そして1.0と3.0を含む変数を宣言することを忘れないでくださいダブルとして...

于 2013-03-05T08:20:21.430 に答える
0

数学ライブラリがない場合は、次の方法を使用して立方根を計算できます。

立方根

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 / bxx

平方根と立方根 (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_1last_b_2は対照的に、立方根では b がちらつくので必要です。これらのアルゴリズムを変更して、4 乗根、5 乗根などを計算できます。

このアルゴリズムを教えてくれた 11 年生の数学教師 Herr Brenner に感謝しますsqrt

パフォーマンス

私は16mhzのクロック周波数を持つArduinoでそれをテストしました:

于 2015-02-02T07:42:19.097 に答える
0

累乗と数の n 乗根を混同すべきではないと思います。古き良きウィキペディアを参照してください

于 2010-11-24T16:36:59.420 に答える
0

これが私がノックアップした小さな機能です。

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

Newton-Raphson を使用して立方根を見つけます。

根が 0 に非常に近い場合、微分が大きくなり、振動する可能性があります。そのため、それが発生した場合は、クランプして強制的に再起動しました。さらに精度が必要な場合は、FLT_EPSILON を変更できます。

于 2014-02-26T13:54:18.430 に答える