数の立方根を見つけようとすると、奇妙なことが起こります。
次のコードは私に未定義を返します。 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++ 2010math.hライブラリからのものです。何か案は?
_<cmath>
_のpow(x, y)
は、xが負で、yが非整数の場合は機能しません。
これは、C標準および cppreference に記載されているように、_std::pow
_の制限です。
エラー処理
- エラーはmath_errhandlingで指定されたとおりに報告されます
- baseが有限で負で、expが有限で非整数の場合、ドメインエラーが発生し、範囲エラーが発生する可能性があります。
- Baseがゼロでexpがゼロの場合、ドメインエラーが発生する可能性があります。
- 底がゼロでexpが負の場合、ドメインエラーまたは極エラーが発生する可能性があります。
この制限を回避するには、いくつかの方法があります。
キューブルート化は、何かを1/3の累乗にすることと同じであるため、std::pow(x, 1/3.)
を実行できます。
C++ 11では、 _std::cbrt
_ を使用できます。 C++ 11では、平方根関数と立方根関数の両方が導入されましたが、_std::pow
_の制限を克服する一般的なn乗根関数はありませんでした。
パワー_1/3
_は特別な場合です。一般に、負の数の非整数乗は複雑です。 powが整数の根のような特殊なケースをチェックすることは実用的ではありません。さらに、doubleとしての_1/3
_は正確に1/3ではありません!
Visual C++のパワーについてはわかりませんが、私のマニュアルページにはエラーが表示されています。
EDOM
引数x
は負であり、y
は整数値ではありません。これにより、複素数になります。
負の数の立方根が必要な場合は、より特殊な立方根関数を使用する必要があります。または、角を切り、絶対値を取り、次に立方根を取り、次に符号を乗算します。
コンテキストによっては、負の数x
の_1/3
_乗は、必ずしも期待する負の立方根ではないことに注意してください。簡単に最初の複素根x^(1/3) * e^(pi*i/3)
になる可能性があります。これは数学が使用する慣習です。未定義だと言うのも合理的です。
(-1)^ 3 = -1の場合、単純に負の数の有理数を取り、実際の応答を期待することはできません。これは、この有理指数には、本質的に虚数である他の解決策があるためです。
http://www.wolframalpha.com/input/?i=x^(1/3)、+ x + from + -5 + to +
同様に、x ^ xをプロットします。 x = -1/3の場合、これには解決策があります。ただし、この関数は、x <0のRでは未定義と見なされます。
したがって、math.hが非効率になるような魔法を実行することを期待せず、自分で記号を変更するだけです。
ネガを取り出して、後で入れないといけないと思います。本当に必要な場合は、ラッパーにこれを実行させることができます。
function yourPow(double x, double y)
{
if (x < 0)
return -1.0 * pow(-1.0*x, y);
else
return pow(x, y);
}
pow( x, y )
はexp( y * log( x ) )
と同じです(つまり、同等です)
log(x)が無効な場合、pow(x、y)も無効です。
同様に、数学的には0である必要がありますが、0の累乗を実行することはできません。
(double)
を使用してdouble
にキャストしないでください。代わりに、二重数値定数を使用してください。
double thingToCubeRoot = -20.*3.2+30;
cout<< thingToCubeRoot/fabs(thingToCubeRoot) * pow( fabs(thingToCubeRoot), 1./3. );
トリックを行う必要があります!
また、C++プロジェクトに<math.h>
を含めないでください。代わりに、<cmath>
を使用してください。
または、buddhabrotが述べた理由により、<complex>
ヘッダーからpow
を使用します
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 でのテストは_x<0
_の場合、C++(gcc-4.8.1)がこのルールcbrt(x)=-cbrt(-x)
で立方根を拡張することを確認します。この拡張機能については、 http://mathworld.wolfram.com/CubeRoot.html を参照してください。
キュビットルートを探していたところ、このスレッドが見つかりました。次のコードが機能する可能性があります。
#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;
}
これが私がノックアップした小さな関数です。
#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_EPSILONを変更できます。
べき乗と数値のn乗根を混同しないでください。古き良き時代を見る ウィキペディア
数学ライブラリがない場合は、次の方法で立方根を計算できます。
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
の立方根に近くなります。
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がちらつくため、立方根に必要です。これらのアルゴリズムを変更して、4番目のルート、5番目のルートなどを計算できます。
sqrt
のこのアルゴリズムを教えてくれた11年生の数学の先生HerrBrennerに感謝します。
私は16MHzのクロック周波数でArduinoでそれをテストしました:
1/3は整数と見なされるため、常に0を返すため... 1.0/3.0で試してください...それは私が思うことですが、実装してみてください...そして1.0と3.0を含む変数を宣言することを忘れないでくださいダブルとして...