快速多体重力算法?
我正在编写一个程序来模拟 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 坐标(二维)超过一定量(由其质量的乘积确定)的物体之间的关系?抱歉,如果这听起来像是我在胡言乱语,但是我可以做些什么来加快速度吗?我宁愿保持它任意精确,但如果有解决方案可以以牺牲一点精度为代价来降低这个问题的复杂性,我会有兴趣听到它。
谢谢。
I am writing a program to simulate an n-body gravity system, whose precision is arbitrarily good depending on how small a step of "time" I take between each step. Right now, it runs very quickly for up to 500 bodies, but after that it gets very slow since it has to run through an algorithm determining the force applied between each pair of bodies for every iteration. This is of complexity n(n+1)/2 = O(n^2), so it's not surprising that it gets very bad very quickly. I guess the most costly operation is that I determine the distance between each pair by taking a square root. So, in pseudo code, this is how my algorithm currently runs:
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)
}
}
So, is there any way I can optimize this? Any fancy algorithms to reuse the distances used in past iterations with fast modification? Are there any lossy ways to reduce this problem? Perhaps by ignoring the relationships between objects whose x or y coordinates (it's in 2 dimensions) exceed a certain amount, as determined by the product of their masses? Sorry if it sounds like I'm rambling, but is there anything I could do to make this faster? I would prefer to keep it arbitrarily precise, but if there are solutions that can reduce the complexity of this problem at the cost of a bit of precision, I'd be interested to hear it.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
看看这个问题。您可以将对象划分为网格,并利用许多远处对象可以被视为单个对象的事实来获得良好的近似值。细胞的质量等于其所含物体的质量之和。细胞的质心可以被视为细胞本身的中心,或更准确地说是 barycenter< /a> 它包含的对象。在平均情况下,我认为这会给你 O(n log n) 性能,而不是 O(n2),因为您仍然需要计算每个 n 个对象上的重力,但每个对象仅与附近的对象单独相互作用。
假设您使用 r2 = x2+ 计算距离y2,然后计算力F = Gm1m2 / ;r2,根本不需要执行平方根。如果您确实需要实际距离,可以使用快速平方根反比。您还可以使用定点算术。
Take a look at this question. You can divide your objects into a grid, and use the fact that many faraway objects can be treated as a single object for a good approximation. The mass of a cell is equal to the sum of the masses of the objects it contains. The centre of mass of a cell can be treated as the centre of the cell itself, or more accurately the barycenter of the objects it contains. In the average case, I think this gives you O(n log n) performance, rather than O(n2), because you still need to calculate the force of gravity on each of n objects, but each object only interacts individually with those nearby.
Assuming you’re calculating the distance with r2 = x2 + y2, and then calculating the force with F = Gm1m2 / r2, you don’t need to perform a square root at all. If you do need the actual distance, you can use a fast inverse square root. You could also used fixed-point arithmetic.
一种好的有损方法是运行聚类算法将物体聚类在一起。
有一些聚类算法相当快,诀窍是不要每次都运行聚类算法。相反,每隔 C 个周期运行一次(C>1)。
然后对于每个簇,计算簇中所有物体之间的力,然后对于每个簇计算簇之间的力。
这会有损失,但我认为这是一个很好的方法。
您必须摆弄:
因此,这将是一场速度与准确性的游戏,但至少这样您将能够牺牲一点准确性来获得一些速度增益 - 使用您当前的方法,您没有什么可以真正调整的全部。
One good lossy approach would be to run a clustering algorithm to cluster the bodies together.
There are some clustering algorithms that are fairly fast, and the trick will be to not run the clustering algorithm every tick. Instead run it every C ticks (C>1).
Then for each cluster, calculate the forces between all bodies in the cluster, and then for each cluster calculate the forces between the clusters.
This will be lossy but I think it is a good approach.
You'll have to fiddle with:
So it's going to be a game of speed vs accuracy, but at least this way you will be able to sacrafice a bit of accuracy for some speed gains - with your current approach there's nothing you can really tweak at all.
您可能想尝试不太精确的平方根版本。您可能不需要完整的双精度。特别是如果坐标系的数量级通常相同,那么您可以使用截断的泰勒级数来快速估计平方根运算,而不会放弃太多的效率。
You may want to try a less precise version of square root. You probably don't need a full double precision. Especially if the order of magnitude of your coordinate system is normally the same, then you can use a truncated taylor series to estimate the square root operation pretty quickly without giving up too much in efficiency.
对于 n 体问题,有一个非常好的近似方法,速度更快(对于朴素算法,O(n log n) vs O(n²)),称为 巴恩斯小屋。空间被细分为分层网格,在计算远距离质量的力贡献时,可以将多个质量视为一个。有一个精度参数可以根据您愿意为计算速度牺牲精度的程度进行调整。
There is a very good approximation to the n-body problem that is much faster (O(n log n) vs O(n²) for the naive algorithm) called Barnes Hut. Space is subdivided into a hierarchical grid, and when computing force contribution for distant masses, several masses can be considered as one. There is an accuracy parameter that can be tweaked depending on how much your willing to sacrifice accuracy for computation speed.