質問
数字のキューブルートを見つけようとすると奇妙なことが起こります。
次のコードは私を未定義に返します。 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ライブラリからのものです。何か案は?
解決
pow(x, y)
から <cmath>
xが負でyが非統合である場合、機能しません。
これはの制限です std::pow
, 、C標準およびオンで文書化されています cppreference:
エラー処理
- エラーは、math_errhandlingで指定されているように報告されます
- ベースが有限で負で、EXPが有限で非整数である場合、ドメインエラーが発生し、範囲エラーが発生する可能性があります。
- ベースがゼロで、EXPがゼロの場合、ドメインエラーが発生する可能性があります。
- ベースがゼロで、EXPが負の場合、ドメインエラーまたはポールエラーが発生する可能性があります。
この制限にはいくつかの方法があります。
キューブルートは1/3のパワーに何かを取ることと同じなので、できます
std::pow(x, 1/3.)
.C ++ 11では、使用できます
std::cbrt
. 。 C ++ 11は、方形ルートとキューブルートの両方の関数を導入しましたが、の制限を克服する一般的なn番目のルート関数はありませんstd::pow
.
他のヒント
パワー 1/3
特別なケースです。一般に、負の数の非統合力は複雑です。 POWが整数の根のような特別なケースをチェックすることは実用的ではありません。 1/3
ダブルは正確に1/3ではありません!
私は視覚的なC ++ Powについては知りませんが、私の男のページはエラーの下で言っています:
EDOM
議論x
ネガティブですy
不可欠な値ではありません。これにより、複雑な数が生じます。
マイナス数のキューブの根が必要な場合は、より専門的なキューブルート関数を使用するか、コーナーを切り取って絶対値を取得し、キューブルートを取り、サインを再び掛けます。
コンテキストに応じて、負の数に注意してください x
に 1/3
パワーは必ずしもあなたが期待しているネガティブキューブルートではありません。それは同じくらい簡単に最初の複雑なルートになる可能性があります、 x^(1/3) * e^(pi*i/3)
. 。これは、Mathematicaが使用するコンベンションです。また、それが未定義だと言うことも合理的です。
一方、(-1)^3 = -1は、単に負の数の合理的な力を持ち、実際の応答を期待することはできません。これは、本質的に想像上のこの合理的な指数に他の解決策があるためです。
http://www.wolframalpha.com/input/?i=x^(1/3),+x+ from from from-from-to+0
同様に、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);
}
キャストしないでください double
使用して (double)
, 、代わりに二重数値定数を使用します。
double thingToCubeRoot = -20.*3.2+30;
cout<< thingToCubeRoot/fabs(thingToCubeRoot) * pow( fabs(thingToCubeRoot), 1./3. );
トリックをする必要があります!
また、含めないでください <math.h>
C ++プロジェクトでは使用します <cmath>
代わりは。
または、使用してください pow
から <complex>
仏教が述べた理由のためにヘッダー
pow( x, y )
(つまり、同等)と同じです exp( y * log( x ) )
log(x)が無効である場合、pow(x、y)もそうです。
同様に、数学的には0である必要がありますが、何のパワーに対して0を実行することはできません。
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
私はキュービットルートを探していましたが、このスレッドを見つけましたが、次のコードが機能する可能性があることがわかります。
#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;
}
指数を数字のnth-rootと混同してはならないと思います。古き良きを見てください ウィキペディア
1/3は整数と見なされるため、常に0を返します... 1.0/3.0で試してみてください...それは私が思うが実装しようとするものです...そして1.0と3.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;
}
ニュートンラフソンを使用してキューブルートを見つけます。
ニュートン - ラフソンが立ち往生します。ルートが0に非常に近い場合、微分が大きくなり、振動することがあります。それで、私はそれが起こった場合にそれを再起動するように固定し、強制しました。より精度が必要な場合は、FLT_EPSILONSを変更できます。
数学ライブラリがない場合は、この方法を使用して立方体のルートを計算できます。
立方根
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はフリッカーであるため、立方体で必要です。これらのアルゴリズムを変更して、4番目のルート、5番目のルートなどを計算できます。
11年生の私の数学の先生であるHerr Brennerに感謝します。 sqrt
.
パフォーマンス
16MHzのクロック周波数のArduinoでテストしました。