部分分析
我可以肯定,问题主要是由于主代码中大量重复的代码(接近重复的代码)
else
第条,共条
quadtree_insert()
.我在开头写了一些评论
Fragment 1A
和
Fragment 1B
片段1B现在也有
#ifdef DO_REPEAT
和
#endif
.
else
{
double x;
double y;
if (width < 1e-300)
{
width = 1e-300;
}
if (n->is_leaf == 1)
{
x = (double)n->p->x_pos;
y = (double)n->p->y_pos;
if (x <= center_x && y <= center_y)
{
n->sw = quadtree_insert(n->sw, n->p, center_x * 0.5, center_y * 0.5, width * 0.5);
}
else if (x <= center_x && y > center_y)
{
n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
else if (x > center_x && y <= center_y)
{
n->se = quadtree_insert(n->se, n->p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
}
else
{
n->ne = quadtree_insert(n->ne, n->p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
n->p = NULL;
n->is_leaf = 0;
}
x = (double)p->x_pos;
y = (double)p->y_pos;
if (x <= center_x && y <= center_y)
{
n->sw = quadtree_insert(n->sw, p, center_x * 0.5, center_y * 0.5, width * 0.5);
}
else if (x <= center_x && y > center_y)
{
n->nw = quadtree_insert(n->nw, p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
else if (x > center_x && y <= center_y)
{
n->se = quadtree_insert(n->se, p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
}
else
{
n->ne = quadtree_insert(n->ne, p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
return n;
}
我把你的代码重新排序了一些片段,并使用了这个
main()
注意,我本不需要这样做;你应该制作一个MCVE(
How to create a Minimal, Complete, and Verifiable Example?
)或SSCCE(
Short, Self-Contained, Correct Example
)两个名称和链接用于相同的基本思想。
static struct Particle particles[] =
{
{ 19.99, 96.07, 62.79, -99.46, 19.70 },
{ 12.94, 1.43, -33.45, 31.80, -66.08 },
{ 6.49, 16.99, -20.83, 92.51, 35.98 },
{ 17.01, -28.85, -94.10, 42.82, -1.30 },
{ 14.27, 85.07, 88.21, 11.22, 16.85 },
{ 15.73, -56.37, 46.85, 27.40, -15.15 },
{ 1.53, -49.44, -64.27, -29.45, -38.25 },
{ 8.03, 92.11, -47.50, 63.77, -29.99 },
{ 8.67, -99.81, 73.19, 18.75, 88.66 },
{ 16.36, 66.33, 14.23, 87.65, 40.01 },
};
enum { nParticles = sizeof(particles) / sizeof(particles[0]) };
int main(void)
{
node *root = NULL;
printf("Particle 0:\n");
root = quadtree_insert(root, &particles[0], 0.500, 0.5, 1);
for (int i = 1; i < nParticles; i++)
{
printf("Particle %d:\n", i);
quadtree_insert(root, &particles[i], 0.5000, 0.5, 1);
}
return 0;
}
我使用随机数生成器生成值表:
random -n 10 -T ' { %6:2[1:20]f, %6:2[-100:100]f, %6:2[-100:100]f, %6:2[-100:100]f, %6:2[-100:100]f },'
它在粒子6上为我崩溃了。大体上,
valgrind
说:
â¦startup blurb omittedâ¦
Particle 0:
Particle 1:
Particle 2:
Particle 3:
Particle 4:
Particle 5:
Particle 6:
==79528==
==79528== Process terminating with default action of signal 11 (SIGSEGV)
==79528== Access not within mapped region at address 0x104003FD0
==79528== at 0x100008E39: malloc (vg_replace_malloc.c:302)
==79528== If you believe this happened as a result of a stack
==79528== overflow in your program's main thread (unlikely but
==79528== possible), you can try to increase the size of the
==79528== main thread stack using the
==79528== The main thread stack size used in this run was 8388608.
==79528==
==79528== HEAP SUMMARY:
==79528== in use at exit: 6,017,700 bytes in 75,080 blocks
==79528== total heap usage: 75,162 allocs, 82 frees, 6,023,876 bytes allocated
==79528==
==79528== LEAK SUMMARY:
==79528== definitely lost: 4,120 bytes in 2 blocks
==79528== indirectly lost: 2,288 bytes in 6 blocks
==79528== possibly lost: 4,880 bytes in 45 blocks
==79528== still reachable: 5,997,720 bytes in 74,904 blocks
==79528== suppressed: 8,692 bytes in 123 blocks
==79528== Rerun with
即使在我运行它的Mac电脑上,这也表明存在问题;被压制的东西是可以的,但其余的大部分都不行。
编译时没有
-DDO_REPEAT
(正常编译),示例程序运行至完成。当然,它会泄漏,因为没有代码来释放内存。
Particle 0:
Particle 1:
Particle 2:
Particle 3:
Particle 4:
Particle 5:
Particle 6:
Particle 7:
Particle 8:
Particle 9:
==79683==
==79683== HEAP SUMMARY:
==79683== in use at exit: 26,580 bytes in 191 blocks
==79683== total heap usage: 273 allocs, 82 frees, 32,756 bytes allocated
==79683==
==79683== LEAK SUMMARY:
==79683== definitely lost: 4,200 bytes in 3 blocks
==79683== indirectly lost: 2,368 bytes in 7 blocks
==79683== possibly lost: 4,880 bytes in 45 blocks
==79683== still reachable: 6,440 bytes in 13 blocks
==79683== suppressed: 8,692 bytes in 123 blocks
==79683== Rerun with
请注意,使用的内存比以前少得多。
如果由于缺少
DO_REPEAT
事实上是至关重要的,那么bug要么存在于代码中,要么存在于片段1A中完成的设置工作中。然而,在我看来,使用递归调用两次插入相同的粒子可能是问题的根源。
我还注意到
quadtree_calculate_forcey()
代码中未使用函数;这绝对不是MCVE的一部分。
需要片段1B
John Bollinger
建议:
请注意,“重复”代码的形式相同,但细节不同。也就是说,片段1B使用
n->p
片段1A使用
p
。我认为这是有目的的:这个想法似乎是将所有数据(粒子)强制输出到叶节点。
和
radnaskela
确认:
正如约翰所说,每个粒子都应该占据一个末端节点。我怀疑这与运动和行星的排列有关,因此要打开两个自由正方形,必须进行荒谬的迭代次数。但我无法找到解决我问题的办法,有什么想法吗?
逻辑有问题,但我不完全确定是什么问题
四叉树插入()
,如下所示:
static node *quadtree_insert(node *n, struct Particle *p, double center_x, double center_y, double width)
{
printf("Centre (X,Y) = (%6.2f,%6.2f)\n", center_x, center_y);
if (n == NULL)
{
n = (node *)malloc(sizeof(node));
n->is_leaf = 1;
n->p = p;
n->sw = NULL;
n->se = NULL;
n->nw = NULL;
n->ne = NULL;
if (width < 1e-300)
{
n->width = 1e-300;
}
else
n->width = width;
return n;
}
else
{
double x;
double y;
if (width < 1e-300)
{
width = 1e-300;
}
if (n->is_leaf == 1)
{
x = (double)n->p->x_pos;
y = (double)n->p->y_pos;
if (x <= center_x && y <= center_y)
{
printf("Recurse SW 1: ");
n->sw = quadtree_insert(n->sw, n->p, center_x * 0.5, center_y * 0.5, width * 0.5);
}
else if (x <= center_x && y > center_y)
{
printf("Recurse NW 1: ");
n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
else if (x > center_x && y <= center_y)
{
printf("Recurse SE 1: ");
n->se = quadtree_insert(n->se, n->p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
}
else
{
printf("Recurse NE 1: ");
n->ne = quadtree_insert(n->ne, n->p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
n->p = NULL;
n->is_leaf = 0;
}
x = (double)p->x_pos;
y = (double)p->y_pos;
if (x <= center_x && y <= center_y)
{
printf("Recurse SW 2: ");
n->sw = quadtree_insert(n->sw, p, center_x * 0.5, center_y * 0.5, width * 0.5);
}
else if (x <= center_x && y > center_y)
{
printf("Recurse NW 2: ");
n->nw = quadtree_insert(n->nw, p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
else if (x > center_x && y <= center_y)
{
printf("Recurse SE 2: ");
n->se = quadtree_insert(n->se, p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
}
else
{
printf("Recurse NE 2: ");
n->ne = quadtree_insert(n->ne, p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
return n;
}
}
使用10点数据集运行时,粒子5的输出为:
Particle 0: Centre (X,Y) = ( 0.50, 0.50)
Particle 1: Centre (X,Y) = ( 0.50, 0.50)
Recurse NE 1: Centre (X,Y) = ( 0.75, 0.75)
Recurse SE 2: Centre (X,Y) = ( 0.75, 0.25)
Particle 2: Centre (X,Y) = ( 0.50, 0.50)
Recurse SE 2: Centre (X,Y) = ( 0.75, 0.25)
Recurse SE 1: Centre (X,Y) = ( 1.12, 0.12)
Recurse SE 2: Centre (X,Y) = ( 1.12, 0.12)
Recurse SE 1: Centre (X,Y) = ( 1.69, 0.06)
Recurse SE 2: Centre (X,Y) = ( 1.69, 0.06)
Recurse SW 1: Centre (X,Y) = ( 0.84, 0.03)
Recurse SE 2: Centre (X,Y) = ( 2.53, 0.03)
Particle 3: Centre (X,Y) = ( 0.50, 0.50)
Recurse SW 2: Centre (X,Y) = ( 0.25, 0.25)
Particle 4: Centre (X,Y) = ( 0.50, 0.50)
Recurse NE 2: Centre (X,Y) = ( 0.75, 0.75)
Recurse NE 1: Centre (X,Y) = ( 1.12, 1.12)
Recurse NE 2: Centre (X,Y) = ( 1.12, 1.12)
Recurse NE 1: Centre (X,Y) = ( 1.69, 1.69)
Recurse NE 2: Centre (X,Y) = ( 1.69, 1.69)
Recurse NE 1: Centre (X,Y) = ( 2.53, 2.53)
Recurse NE 2: Centre (X,Y) = ( 2.53, 2.53)
Recurse NE 1: Centre (X,Y) = ( 3.80, 3.80)
Recurse NE 2: Centre (X,Y) = ( 3.80, 3.80)
Recurse NE 1: Centre (X,Y) = ( 5.70, 5.70)
Recurse NE 2: Centre (X,Y) = ( 5.70, 5.70)
Recurse NE 1: Centre (X,Y) = ( 8.54, 8.54)
Recurse NE 2: Centre (X,Y) = ( 8.54, 8.54)
Recurse NE 1: Centre (X,Y) = ( 12.81, 12.81)
Recurse NE 2: Centre (X,Y) = ( 12.81, 12.81)
Recurse NE 1: Centre (X,Y) = ( 19.22, 19.22)
Recurse NE 2: Centre (X,Y) = ( 19.22, 19.22)
Recurse NE 1: Centre (X,Y) = ( 28.83, 28.83)
Recurse NE 2: Centre (X,Y) = ( 28.83, 28.83)
Recurse NE 1: Centre (X,Y) = ( 43.25, 43.25)
Recurse NE 2: Centre (X,Y) = ( 43.25, 43.25)
Recurse NE 1: Centre (X,Y) = ( 64.87, 64.87)
Recurse NE 2: Centre (X,Y) = ( 64.87, 64.87)
Recurse SE 1: Centre (X,Y) = ( 97.31, 32.44)
Recurse NE 2: Centre (X,Y) = ( 97.31, 97.31)
Particle 5: Centre (X,Y) = ( 0.50, 0.50)
Recurse NW 2: Centre (X,Y) = ( 0.25, 0.75)
我对其中的一些处理过程以及粒子4的条目数感到有点惊讶。这可能表明了问题所在。
然后处理粒子6:
Particle 6: Centre (X,Y) = ( 0.50, 0.50)
Recurse SW 2: Centre (X,Y) = ( 0.25, 0.25)
Recurse SW 1: Centre (X,Y) = ( 0.12, 0.12)
Recurse SW 2: Centre (X,Y) = ( 0.12, 0.12)
Recurse SW 1: Centre (X,Y) = ( 0.06, 0.06)
Recurse SW 2: Centre (X,Y) = ( 0.06, 0.06)
Recurse SW 1: Centre (X,Y) = ( 0.03, 0.03)
Recurse SW 2: Centre (X,Y) = ( 0.03, 0.03)
Recurse SW 1: Centre (X,Y) = ( 0.02, 0.02)
Recurse SW 2: Centre (X,Y) = ( 0.02, 0.02)
Recurse SW 1: Centre (X,Y) = ( 0.01, 0.01)
Recurse SW 2: Centre (X,Y) = ( 0.01, 0.01)
Recurse SW 1: Centre (X,Y) = ( 0.00, 0.00)
Recurse SW 2: Centre (X,Y) = ( 0.00, 0.00)
Recurse SW 1: Centre (X,Y) = ( 0.00, 0.00)
Recurse SW 2: Centre (X,Y) = ( 0.00, 0.00)
Recurse SW 1: Centre (X,Y) = ( 0.00, 0.00)
Recurse SW 2: Centre (X,Y) = ( 0.00, 0.00)
从那以后,它变得非常乏味。你需要问的问题是“那一点应该发生什么”?最好也有一个函数来转储四叉树结构。
这基本上表明,您尚未分析要充分添加点的条件。我不清楚为什么在插入位于SE或NE象限时将中心坐标乘以1.5,在SW或NW象限时乘以0.5(也不清楚为什么使用加法+乘法而不是简单的乘法)。
上的测试
width
少于
1e-300
有点令人担忧。假设您使用值调用函数
1.0
,每次递归时将宽度减半,需要一段时间才能得到如此小的值。
更好的跟踪很可能会报告
x
和
y
以及中心坐标。