Java 快速多体重力算法?

Java 快速多体重力算法?,java,optimization,simulation,gravity,Java,Optimization,Simulation,Gravity,我正在编写一个程序来模拟一个n体重力系统,它的精度是任意好的,这取决于我在每一步之间的“时间”步长有多小。现在,它运行速度非常快,最多可运行500个物体,但之后运行速度会非常慢,因为它必须通过一个算法来确定每次迭代时在每对物体之间施加的力。这是一个复杂度为n(n+1)/2=O(n^2)的过程,所以它很快变得非常糟糕也就不足为奇了。我猜最昂贵的操作是通过平方根来确定每对之间的距离。因此,在伪代码中,我的算法目前是这样运行的: for (i = 1 to number of bodies - 1)

我正在编写一个程序来模拟一个n体重力系统,它的精度是任意好的,这取决于我在每一步之间的“时间”步长有多小。现在,它运行速度非常快,最多可运行500个物体,但之后运行速度会非常慢,因为它必须通过一个算法来确定每次迭代时在每对物体之间施加的力。这是一个复杂度为n(n+1)/2=O(n^2)的过程,所以它很快变得非常糟糕也就不足为奇了。我猜最昂贵的操作是通过平方根来确定每对之间的距离。因此,在伪代码中,我的算法目前是这样运行的:

for (i = 1 to number of bodies - 1) {
  for (j = i to number of bodies) {
   (determining the force between the two objects i and j,
    whose most costly operation is a square root)
  }
}
那么,我有什么办法可以优化它吗?有没有什么花哨的算法可以通过快速修改重用过去迭代中使用的距离?有没有减少这个问题的有损方法?也许通过忽略x或y坐标(在二维中)超过一定数量的对象之间的关系(由其质量的乘积决定)?对不起,如果这听起来像我在胡扯,但有什么我可以做的,使这更快?我更愿意保持它的任意精确性,但如果有解决方案可以降低这个问题的复杂性,而牺牲一点精确性,我会很有兴趣听到它


谢谢。

一个很好的有损方法是运行一个程序将身体聚集在一起

有一些聚类算法相当快,诀窍是不要每次都运行聚类算法。而是每隔一个周期运行一次(C>1)

然后,为每个簇计算簇中所有实体之间的力,然后为每个簇计算簇之间的力

这将是有损的,但我认为这是一个好办法

你将不得不摆弄:

  • 使用哪种聚类算法:一些更快,一些更准确。有些是确定性的,有些不是
  • 运行集群算法的频率:运行得越少,速度越快,运行得越多,精度越高
  • 集群的大小:大多数集群算法允许您输入集群的大小。您允许的集群越大,输出速度就越快,但精度就越低
因此,这将是一场速度与准确性的游戏,但至少通过这种方式,你将能够牺牲一点准确性来获得一些速度增益-以你目前的方法,你根本无法调整任何东西。

看看。您可以将对象划分为网格,并利用许多远处的对象可以作为单个对象处理的事实,获得良好的近似效果。单元的质量等于其包含的对象的质量之和。细胞的质心可以被视为细胞本身的中心,或者更准确地说是细胞所包含的物体的中心。在一般情况下,我认为这会提供O(n logn)性能,而不是O(n2),因为您仍然需要计算n个对象中每个对象上的重力,但每个对象仅与附近的对象单独交互


假设你用r2=x2+y2计算距离,然后用F=Gm1m2/r2计算力,你根本不需要进行平方根运算。如果您确实需要实际距离,可以使用。您也可以使用。

您可能需要尝试精度较低的平方根。您可能不需要完全的双精度。特别是如果坐标系的数量级通常是相同的,那么可以使用截断的泰勒级数快速估计平方根运算,而不会放弃太多效率。

也许我是稠密的,但你不是用sqrt(x^2+y^2)得到距离吗然后立即将它平方为G*m1*m2/r^2,得到力?你不能把平方根全部去掉吗?@JamesMoughan,那不行。因为你不想计算力的绝对值,而是要计算力向量。在这个公式中,你可以得到
r_-vec/Abs(r)^3
,但这里的主要问题不是平方根的成本。这是因为该算法在对象数量上是二次的。使用将对象分组的近似值,可以将其缩减为
n*log(n)
或类似的值。正如james所说,可以将平方根全部去掉。我只是用两种方法测试了它,结果是一样的。我不确定如何避免平方根。我也不推荐固定点。与他们一起工作很烦人,我不期望有显著的性能提升。我更愿意研究来自SSE的向量指令,它一次处理多个浮点数。