【问题标题】:How to optimize math with 2D vectors?如何使用二维向量优化数学?
【发布时间】:2014-04-03 14:36:07
【问题描述】:

我正在开发 iOS 应用程序,该应用程序使用一千个对象的数组执行一些计算。对象具有 x 和 y 坐标的属性、x 和 y 轴的速度以及耦合其他 x-y 属性。有一些数学可以计算由数组中的对象表示的物理对象之间的交互。数学很简单,基本上是计算施加在物体上的力、速度和每个物体的位置变化 (x,y)。我在 Objective C 中使用常规标量数学编写了一个代码,它在 iPhone 5s 上运行良好,但在 iPhone 4、4s、5 和 iPad mini 等其他设备上却太慢了。我发现最耗时的操作是计算 2 点之间的距离和计算向量的长度,如下所示,其中涉及取平方根:

float speed = sqrtf(self.dynamic.speed_x,2)+pow(self.dynamic.speed_y,2));

所以,我必须做一些事情来加快计算速度。我重新编写了代码以使具有对象坐标的属性以及由 X 和 Y 分量呈现的速度等属性成为 GLKVector2 类型的向量。我希望它可以使变量的计算,如 2 个向量(或点,根据我的理解)之间的距离,由于使用 GLKVector2Distance、GLKVector2Normalize、GLKVector2Add 等特殊向量函数而显着加快向量的加法和减法。但是,它在性能方面并没有太大帮助,因为我相信,要将具有 GLKVector2 类型属性的对象放入数组中,我必须使用 NSValue,以及将 GLKVector2 值从对象中解码回来数组来执行向量计算。下面是对象实现中计算方法的代码:

GLKVector2 currentPosition;
[self.currentPosition getValue:&currentPosition];
GLKVector2 newPosition;


// calculations with vectors. Result is in newPosition.

self.currentPosition = [NSValue value:&newPosition withObjCType:@encode(GLKVector2)];

此外,当我重写代码以使用 GLKVector2 时,我收到了内存警告,并且在运行应用程序一段时间后有时会崩溃。

我花了几天时间试图找到一种更好的方法来更快地进行计算,我查看了 vecLib、openGL,但没有找到我可以理解的解决方案。我有一种感觉,我可能不得不考虑用 C 编写代码并将其以某种方式集成到目标 C 中,但我不明白如何在不使用 NSValue 数千次的情况下将其与对象数组集成。

如果有人能就我应该关注的方向提供建议,我将不胜感激?也许有一些可用的库可以在 Objective C 中轻松使用,并将一组对象存储在数组中?

【问题讨论】:

    标签: ios math vector


    【解决方案1】:

    这里回答了您有关将 C 中的物理计算与您当前的 Objective-C 类集成的问题。如果您的 .m 文件中有一段 C 代码,可能看起来像

    static CGPoint point[MAX_OBJ];
    static int n_points = 0;
    

    使用纯 C 语言中的相应函数,如您所建议的用于模拟作用于point 以更新对象位置的物理交互,如

    void tick_world() {
        for (int k = 0; k < n_points; k ++) {
            float speed = sqrtf((point[k].x*point[k].x) + (point[k].y*point[k].y));
            ...
        }
    }
    

    那么,移动对象的 Objective-C 类 Moving 可能包含指向 point 中特定 CGPoint 的指针,您将在接口中定义该指针(可能是相应的 *.h 文件):

    @interface Moving : NSObject {
        ...
        CGPoint *pos;
    }
    

    在处理init 消息时,您可以抓取并初始化point 中的下一个可用元素。如果您的对象在整个运行期间持续存在,这可以非常简单地通过

    @implementation 
    ...   
    -(id)initAtX:(float)x0 Y:(float)y0 {
        self = [super init];
        if (self) {
            if (n_points == MAX_OBJ) {
                [self release];
                return nil;
            }
            pos = point + n_points ++;
            pos->x = x0;
            pos->y = y0;
        }
        return self;
    }
    

    如果您的Moving 对象确实持续存在,您可能需要考虑一种聪明的方法来在销毁后回收槽。例如,您可以使用NAN 初始化point 中的所有x,并将其用作定位空闲槽的方法。在您的dealloc 中,您将使用pos-&gt;x = NAN

    【讨论】:

      【解决方案2】:
      1. 了解如何使用仪器。除非您在更改前后测量速度,否则任何性能优化都是毫无意义的。包含 1000 个对象的数组什么都不是,所以您可能什么都不担心。或者减速在一个完全不同的地方。使用仪器。

      2. x * x 是一个乘法。 powf (x, 2.0) 是一个昂贵的函数调用,可能需要 20 到 100 倍的时间。

      3. GLKVector2 是一个原语(它是一个联合)。试图将其存储到 NSValue 中完全没有意义,而且浪费的时间可能比直接存储多 100 倍。

      【讨论】:

      • 感谢您的回答!澄清一下,1)计算周期数不等于一个数组中的对象数。大约有 100,000 次计算,例如 sqrtf(xx+bb)*c 为了测量速度,我使用了 NSTimer。你会推荐什么乐器? 2) x*x 的结果要好得多,但恐怕 sqrtf 比 powf(x,2) 更耗时。 3) 将具有 GLKVector2 作为属性的对象添加到数组中时,无法直接存储 GLKVector2。您将如何直接存储 GLKVector2?
      • 还有一件事,当我将 = sqrtf(xx+yy) 替换为 = 0 时,(没有物理意义)计算的“速度”提高了所以我发现这些特定的操作占用了大约 70% 的时间。
      • 您似乎有一个类型为 NSValue* 的属性。将该属性的类型更改为 GLKVector2。 “时间探查器”应该可以帮助您。为了快速测量,我只使用具有亚微秒精度的 [NSDate date]。
      • 您不能将 GLKVector2 元素放入 NSArray。但是您可以轻松地将 1000 个 GLKVector2 元素放入数组“GLKVector2* array = malloc (1000 * sizeof (*array))”中。访问任何东西都不需要方法调用。
      【解决方案3】:

      听起来您遇到了几个常见问题:1) 高级语言中的快速数学运算,以及 2) 元问题:是否要从其他人的工作中受益(OpenGL,and several ideas listed here ) 以换取作为开发人员的陡峭学习曲线。

      尤其是对于这个主题,我认为使用图书馆是一件好事。对于许多人(例如Eigen)来说,大部分学习曲线是关于 Objective C 和 C++ 的集成,您可以很快将其抛在脑后。

      (顺便说一句,通常情况下,计算对象之间距离的平方就足以进行比较。如果这适用于您的应用程序,您可以通过将distance(a,b) 替换为@ 来节省周期987654324@

      【讨论】:

        猜你喜欢
        • 2012-08-29
        • 1970-01-01
        • 2015-08-27
        • 1970-01-01
        • 2018-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-02
        相关资源
        最近更新 更多