2012-03-14 10 views
0

私は2週間コードに問題があり、デバッグに失敗しました。私は誰かが助けることができるという希望でここに来ました。私は、n-body重力シミュレーションにBarnes-Hutアルゴリズムを利用したプログラムを作成しました。私の問題は、(NaN、NaN、NaN){NaN、NaN、NaN}の位置が1つ以上の「パーティクル」に割り当てられていることです(3次元空間のx、y、zを表すために3つの2倍を使用します)。これにより、他の粒子は{NaN、NaN、NaN}の加速度を持ち、さらに{NaN、NaN、NaN}の速度と位置も持ちます。基本的に、1フレームまたは2フレーム後、すべてが消えます。 updateAccメソッドで発生しているようですが、そうではないと感じています。私はこれが大きな仕事であると理解し、私を助けてくれる誰にとっても非常に感謝しています。 私がチェックしたこと: 負の平方根はなく、すべての値が限界内にあるようです。 ソースコードはhereです。再度、感謝します。 NaNを生成するようだNaNに関する問題

コード:

private static void getAcc(particle particle, node node) 
{ 
    if ((node.particle == null && node.children == null) || node.particle == particle) 
    { 
     //Geting gravity to a node that is either empty or the same node... 
    } 
    else if (distance(node.centerOfMass, particle.position)/node.sideLength > theta && node.children != null) 
    { 
     for (int i = 0; i < node.children.length; i++) 
     { 
      if (node.children[i] != null) 
      { 
       getAcc(particle, node.children[i]); 
      } 
     } 
    } 
    else 
    { 
     particle.acceleration = vecAdd(particle.acceleration, vecDiv(getForce(particle.position, particle.mass, node.centerOfMass, node.containedMass), particle.mass)); 
    } 
} 
private static double sumDeltaSquare(double[] pos1, double[] pos2) 
{ 
    return Math.pow(pos1[0]-pos2[0],2)+Math.pow(pos1[1]-pos2[1],2)+Math.pow(pos1[2]-pos2[2],2); 
} 
private static double[] getForce(double[] pos1, double m1, double[] pos2, double m2) 
{ 
    double ratio = G*m1*m2; 
    ratio /= sumDeltaSquare(pos1, pos2); 
    ratio /= Math.sqrt(sumDeltaSquare(pos1,pos2)); 
    return vecMul(vecSub(pos2, pos1), ratio); 
} 
private static double distance(double[] position, double[] center) 
{ 
    double distance = Math.sqrt(Math.pow(position[0]-center[0],2) + Math.pow(position[1]-center[1],2) + Math.pow(position[2]-center[2],2)); 
    return distance; 
} 
+1

?そのコードを投稿するとよいでしょう。 – Hidde

+0

それだけです。NaNが実際にどこから来ているのかを特定できませんでした。 – danfoster3141

+5

クローズしてください:見知らぬ人に検査によるコードの100行分のエラーを発見することは生産的ではありません。デバッガー(または多くの印刷ステートメント)を使用して後方にトレースする必要があります。 NaNを生成するどこかの計算が必要です。 –

答えて

0

私はあなたのコードをデバッグするつもりはありません。しかし、NaN値は、浮動小数点数に対する数学的に無効な演算の結果です。それらの中で最も有名なのは0による除算です(浮動小数点で例外をスローしません)。 これはどうしてできますか?

計算結果が非常に小さい場合は、64ビットの浮動小数点数(使用可能なビット数より多いビット数が必要です)として表現するには小さすぎる可能性があり、Javaでは代わりに0.0が返されます。 逆方向では、オーバーフローが発生すると(数字の大きさが多すぎると)、Javaはこれを無限大に変えます。無限大と0で数学を実行すると、NaNにすぐにつながる可能性があり、NaNは適用するすべての操作を伝播します。

詳細については、Java言語仕様のセクション4.2と15.17を参照してください。

+0

0で除算しても一般にNaNは発生しません。 –

+0

Java floatを使用すると、分子の符号に応じて、0で除算するとFloat.NEGATIVE_INFINITYまたはFloat.POSITIVE_INFINITYが返されます。 –

+0

真。私は仕様を少し速く読んだ。 0で除算すると、0.0/0.0のときにNaNだけが返されます。それにもかかわらず、計算を使ってNaNを生成することは、上記のコードの問題とまったく同じです。 – Jochen

1

これが唯一の問題であるかどうかはわかりませんが、開始です。

sumDeltaSquareは時々値がgetForce ratio /= sumDeltaSquare(pos1, pos2);で使用される場合、それは無限大を生成し、問題を引き起こす開始することを意味する0を返します。

これは、すべてを意味するものをデバッグして解決する必要がある深刻な問題です。私は点を見て楽しんだ。

+0

2つの異なる質量が1つの位置を占めるときのみ。私は、あなたが特異点の中に入ることを試みていない限り、重力シミュレータでこれがどれほど頻繁に起こるのかよくわかりません。この場合、NaNは間違いなくより重要なエラーを示します。 –

1

まず、JavaのVecmathライブラリを使用していないのはなぜですか?はあなたの問題は、カスタムベクトル関数のどこかに、非常に可能性があります(Java3Dのバイナリのビルドをダウンロードしてください。Java3Dのの一部として配布してからちょうどvecmath.jar使用しています)。もしそうでなければ、@ pimasterは恐らく大文字の2つが1つのスペースを占めるならば、翻訳の大きさのメソッドsumDeltaSquare0を返している可能性があります。つまり、あなたがブラックホールの中にいなければ、あなたはそれを間違っているのです:P。あるいは、このシミュレーションを行う前に、量子重力理論を考え出す必要があります。

あなたはどんな正規表現の代替*除いて、私はあなたがreturn *のすべてのインスタンスを検索し、assert !Double.isNan(*) && Double.isFinite(*);\nreturn *でそれを置き換えるためにregexを使うことをお勧め(すなわち、これは宿題です)vecmathを使用できない場合は、「一致グループを見つけました"私はそれが何であるかを忘れてしまったが、私はあなたをGoogleで始めた。私はまた、あなたがた後に、コードを作業するまで最適化を避けることをお勧めします。第一の粒子は、それらの座標が由来しない{NaNでのNaNはNaN}座標を割り当てられる

+0

それは 'Double.NaN!= Double.NaN'のため' assert'は常にパスします。 'assert! Double.isNaN(...); '代わりに –