n k関数を選択してくださいrcpp.
-
20-12-2019 - |
質問
私はC ++でkを選択した。これはRCPPを介してRとインタフェースしている。何らかの理由で 'ゼロ'ランタイムエラーで除算されています。30を選択しようとすると起こります2.
手動で各行を評価しようとしましたが、ゼロの除算が起こっている場所についてまだ困惑しています。多分誰かが私にこれを指摘したり、より良い執筆方法を指摘することができる
これはコードです:
// [[Rcpp::export]]
int chooseC(int n, int k) {
if (k > n) {
std::cout << "Error. k cannot be greater than n." << std::endl;
return 0;
}
int factN = std::tgamma(n + 1);
int factK = std::tgamma(k + 1);
int factDiff = std::tgamma(n - k + 1);
return factN/(factK*factDiff);
}
. 解決
簡単に:
-
私が見ることができる限りtgammaはありません
-
R自体は
choose
関数として 以下のことをするでしょう
-
rもガンマ分布などを持っているので、これを手で
にすることができます
-
値
factN
、factK
、factDiff
を印刷しなかったのはなぜですか。
簡易RCPPソリューション:
#include <Rcpp.h>
// [[Rcpp::export]]
double chooseC(double n, double k) {
return Rf_choose(n, k);
}
.
例:
R> chooseC(5,2)
[1] 10
R>
.
編集: C ++ 11 tgamma()
ヘッダのcmath
についての@BlastFurnaceによるコメントに続いて、ここには、私にとって正常に機能する修復版があります:
#include <Rcpp.h>
#include <cmath>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
int chooseCtake2(int n, int k) {
if (k > n) {
Rcpp::stop("Error. k cannot be greater than n.");
}
int factN = std::tgamma(n + 1);
int factK = std::tgamma(k + 1);
int factDiff = std::tgamma(n - k + 1);
return factN/(factK*factDiff);
}
.
使用例:
R> sourceCpp("/tmp/chooseC.cpp")
R> chooseCtake2(2,3)
Error: Error. k cannot be greater than n.
R> chooseCtake2(5,2)
[1] 10
R>
. 他のヒント
SO std::tgamma(x)
はxのガンマ関数を計算します。この関数は無限大にかなり急速に行く:
http://www.wolframalpha.com/share/clip?f=d41d8cd98f00b204e9800998ecF8427et5pmak8jtn
すでにx== 31では、非常に大きな数字があります。
この非常に大きなダブルをintに変換するとき、結果は未定義の動作です(4.9フローティング積分変換[CONV.FPINT]):
浮動小数点型の角形は、の角形に変換することができます。 整数型。変換が切り捨てられた。つまり、分数部分です 破棄されています。切り捨てられた値ができない場合、動作は未定義です 宛先タイプに表されます。
私のシステムでは、({30,2}の入力を含む)この変換は、値-2147483648のintになります。これはいくつかの印刷ステートメントを挿入することによって簡単に観察されます。
int
chooseC(int n, int k)
{
if (k > n)
{
std::cout << "Error. k cannot be greater than n.\n";
return 0;
}
int factN = std::tgamma(n + 1);
std::cout << "factN = " << factN << '\n';
int factK = std::tgamma(k + 1);
std::cout << "factK = " << factK << '\n';
int factDiff = std::tgamma(n - k + 1);
std::cout << "factDiff = " << factDiff << '\n';
std::cout << "factK*factDiff = " << factK*factDiff << '\n';
return factN/(factK*factDiff);
}
.
私の出力にどちらを出力します:
factN = -2147483648
factK = 2
factDiff = -2147483648
factK*factDiff = 0
.
見ることができるように、UBは最終的にゼロの分割をもたらし、これはUBである。そしてあなたが見ている行動と非常に似ている音。
この問題に対する解決策は、積分演算のみを使用して物を計算することであり、最終結果が積分型で表現可能な場合に中間計算がオーバーフローしないように。これにより、最大の共通除数関数の使用が伴います。
これを行うオープンソースコード:
http://howardhinant.github.io/Combinations.html
「COUNT_EACH_COMBINATION」を検索します。 chooseC
は、count_each_combination
のようにコーディングできます。
int
chooseC(int n, int k)
{
if (k > n)
{
std::cout << "Error. k cannot be greater than n.\n";
return 0;
}
return count_each_combination(n-k, k);
}
.
chooseC(30, 2)
は435を返します.count_each_combination
がint
に結果を格納できない場合、std::overflow_error
がスローされます。
chooseC
をk == 2
に制約したい場合、またはおそらくアルゴリズムをよりよく理解するためだけに、組み合わせをカウントするための式は次のとおりです。
n*(n-1)/2
.