2

私は、多くのクエリと、これらのクエリの結果に基づく数学的モデリング、および最後にいくつかのスコアリングを行うプロジェクトに取り組んでいます (「実行時間が長すぎて完全にテストできません」)。

最近、コードにかなり新しい問題/バグがあることに気付きました。一部の結果NaNはスコアの値を取得します! スコアの計算方法は次のとおりです。

は、常に正または 0 であるpfoundことにpsig注意してくださいdouble

Double  score1 = (pfound!=0) ? (Math.log(factorial((int)psig + 1))/pfound) : 0;

score1 = score1 * alpha_coeff[0];
if (score1.isInfinite())
    throw new RuntimeException(p.getName() + " score1 = Inf");
else if(score1.isNaN())
    throw new RuntimeException(p.getName() + " score1 = NaN");

をトリガーする考えられる原因を確認しましたがNaN、それらのほとんどから安全であると信じています。

  1. 私はすでに pfound == 0 をチェックしています(ゼロ除算はありません)

  2. Math.log() の引数に負の値を指定することはできません

私が疑うのはfactorial()、(階乗を a として返すカスタム関数long)が非常に大きな aを返すかどうかで、精度などを失うことなくlonga にキャストすることはできません。doubleをチェックしたところ、引数の結果が の場合Long.doubleValue()に生成されるようです。NaNNaN

コメントはありますか?ここで何か基本的なことが欠けていますか?

4

3 に答える 3

3

あなたの階乗がxの素朴な評価をしているなら! = 1*2*3...、使用している参照に収まらない数値の階乗を求めているに違いありません。

2 つのアドバイス:

  1. その場合は BigDecimal を試してください
  2. 素朴な実装の代わりにガンマ関数を使用してください。

n > 12 の factorial(n) の再帰は、非常にまずい単純な考えです。このようなことを進めることを真剣に考えていませんでしたね?

于 2010-07-06T17:43:17.777 に答える
2

NaNはさまざまな算術演算を介して伝播するため、ここで条件を正しくチェックしていても、他の場所から導入される可能性があります。

alpha_coeff[0]またはpfoundのいずれかが疑われます-これらのNaNをチェックしてみてください。

NaNは、これがどのように定義されているかに応じて、階乗関数の結果である可能性もあります。編集:これは長いものを生成するため、階乗はNaNを生成できないことを指定したことに気づきました。一方、オーバーフローすると、log()からNaNが発生する可能性があります。

于 2010-07-06T15:39:30.163 に答える
2

double とゼロを明示的に比較するべきではありません。ほとんど機能しません。次のようなことをしたほうがいいです:

double EPS = 0.0000001;
if (Math.abs (pfound) < EPS) { //pfound is null } 

NaN を生成できる唯一の場所は ですMath.log。そのドキュメントから:

  1. 引数が NaN またはゼロ未満の場合、結果は NaN になります。
  2. 引数が正の無限大の場合、結果は正の無限大になります。
  3. 引数が正のゼロまたは負のゼロの場合、結果は負の無限大になります。

pfoundゼロに近い負の値が含まれていると思います。それが NaN を取得する理由です。デバッガーで変数値を追跡してみてください。

于 2010-07-06T15:33:28.273 に答える