NaN的问题

时间:2012-03-14 23:13:35

标签: java double

我的代码问题已经持续了两个星期,并且在调试方面都没有成功。我来这里是希望有人可以提供帮助。我编写了一个程序,利用Barnes-Hut算法进行n体重力模拟。我的问题是一个或多个“粒子”将分配{NaN,NaN,NaN}的位置(使用三个双倍来表示三维空间的x,y,z)。这反过来又使得其他颗粒具有{NaN,NaN,NaN}的加速度,并且又导致{NaN,NaN,NaN}的速度和位置。基本上,在一两帧之后,一切都消失了。它似乎发生在updateAcc方法中,但我有一种感觉,事实并非如此。我知道这是一项艰巨的任务,我非常感谢能帮助我的人。 我检查了什么: 没有负的平方根,所有的值似乎都在他们的范围内。 源代码可用here。再次感谢。

似乎产生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;
}

3 个答案:

答案 0 :(得分:1)

我不确定这是否是唯一的问题,但这是一个开始。

sumDeltaSquare有时会返回0,这意味着当在getForce ratio /= sumDeltaSquare(pos1, pos2);中使用该值时,它将产生无穷大并开始导致问题。

这是一个严重的问题,您需要调试并确定一切意味着什么。我喜欢看点。

答案 1 :(得分:1)

首先,你为什么不使用Java的Vecmath库?(它是作为Java3D的一部分发布的。下载Java3D的二进制构建,然后只使用vecmath.jar)你的问题是很可能,在您的自定义矢量函数中的某个地方。如果没有,@ pimaster可能是正确的,因为如果你的两个群众占据一个空间,你的翻译量值方法sumDeltaSquare可能会返回0。这意味着,除非你在黑洞内,否则你做错了:P。或者你需要先提出量子引力理论才能进行模拟。

如果您不能使用vecmath(即这是一项家庭作业),我建议您使用regex查找return *的每个实例,然后将其替换为assert !Double.isNan(*) && Double.isFinite(*);\nreturn *,除了用*代替正则表达式找到“匹配组”。我已经忘记了那是什么,但我让你开始使用谷歌。我还建议你避免优化,直到之后你有工作代码。

答案 2 :(得分:0)

我不打算调试你的代码。但NaN值是浮点数的数学无效操作的结果。其中最着名的是除以0(不会抛出浮点异常)。 怎么会发生这种情况?

如果您的计算产生非常小的数字,它们可能会变得太小而无法表示为64位浮点数(它们需要的位数多于可用位数),而Java将返回0.0。 在另一个方向,如果你遇到溢出(数字的大小需要太多位),Java会把它变成无穷大。使用无穷大和0进行数学运算可以快速导致NaN,并且NaN会在您应用的每个操作中传播。

有关详细信息,请参阅Java语言规范的第4.2和15.17节。