【发布时间】:2013-05-09 20:12:37
【问题描述】:
我有double x 和double y。我需要将其转换为int boxnum,它被定义为(x,y) 落在WIDTH x HEIGHT 网格中的(下限)索引,其大小为BOX_SIZE。超过WIDTH 的坐标被回绕; HEIGHT 同上。
我目前正在使用:
( (((int)(x))/BOX_SIZE)%WIDTH+ WIDTH*((((int)(y))/BOX_SIZE)%HEIGHT) )
这个语句目前占用了我 20% 的执行时间,如果我让它对负坐标完全安全,情况会变得更糟(大约 40-50%):
( (( ((int)(x)) /BOX_SIZE)%WIDTH+WIDTH)%WIDTH
+WIDTH*(( (((int)(y)) /BOX_SIZE)%HEIGHT+HEIGHT)%HEIGHT) )
我实际上正在考虑将应用程序完全转换为定点,只是为了避免这种情况,这样我就可以掩码掉我想要的部分,而不是进行这种可怕的转换。
有没有更好的方法来进行这种 double->int 转换?确保0<x<WIDTH*BOX_SIZE 和0<y<HEIGHT*BOX_SIZE 这样我可以放弃两个余数操作是否值得? (这样做太难了,不值得作为基准,除非它可能是一个显着的改进)
编辑:在 cmets 进行适当的惩罚后,更多细节:
x 和 y 是一组(多达 10^6 个)粒子的坐标。我正在使用一种算法,该算法要求我在每个时间步长对一个盒子内的所有粒子进行一些简单的求和。因此,我遍历粒子,计算粒子在哪个盒子中,然后将其用作添加到该盒子的数组索引。粒子经常移动得足够远,以至于它们过去的位置并不能表明它们未来的位置。它们也是无序的,这意味着我不能对此做出任何假设。
WIDTH、HEIGHT 和 BOX_SIZE 在技术上是免费的,只要 WIDTH 和 HEIGHT 是 BOX_SIZE 的偶数倍数。实际上,它们都是指定的编译时间,并且是带有BOX_SIZE=1 的整数。我已经运行了从 WIDTH=HEIGHT=4 到 WIDTH=HEIGHT=512 的所有内容,虽然我通常是 2 的平方幂(因为为什么不呢?),WIDTH=37;HEIGHT=193 应该可以正常工作。
这个计算是不可避免的,每个粒子每个时间步执行一次;在当前的实现中,它被执行了两次。我尝试缓存该值以避免重新计算,但最终基准的表现更差,所以我又重新计算了两次。
使用10 particles/box * 100 WIDTH * 100 HEIGHT* 10000 steps = 1 billion particle*timesteps 的基本测试在阴凉处运行了一分钟。
这些坐标的顺序是它们的“常规数字”(1-1000),所以我在double 上没有任何限制。
【问题讨论】:
-
这是哪个更大的算法的一部分? x 和 y 是如何生成或指定的?您是否可以控制 BOX_SIZE、WIDTH 和 HEIGHT 的(大概)常量值?并不是说转换为定点不一定允许您将其更改为掩码操作
-
我认为这是一个与@jerry 的第一个问题类似的问题,只是措辞略有不同:您是否对传递给函数的每个数字执行昂贵的操作?还是只在 x 为负等时对 x 做双余?
-
无法在黑暗中有效地诊断出此类性能问题。相关因素包括 WIDTH 和 HEIGHT 是否是编译时常量、它们的具体值、相对于其他代码执行这些计算的频率、索引中是否有任何可以使用的模式(例如遍历列或对角线)从循环中提升计算,以及 x 和 y 相对于它们的类型的潜在值范围(是否有足够的空间添加 WIDTH 的倍数以便可以消除第一个
%?)。 -
对不起,如果我的评论被认为是责备,那不是我的意图。我猜您正在使用高优化级别进行编译,因此如果您可以通过选择 2 的幂和移位/屏蔽来节省周期,那么您的编译器可能已经这样做了。不过,以防万一,您是否测试过显式移位和屏蔽?
-
你说的“……他们……是
BOX_SIZE=1的整数”是什么意思?
标签: c performance floating-point