【发布时间】:2014-12-11 00:05:15
【问题描述】:
总的来说,我更喜欢用 Java 编程而不是 C++,这主要是因为库的链接要容易得多(没有“依赖地狱”),而且因为有很多开箱即用的功能强大的包。我也喜欢 jMonkey 和 Processing 等 java 工具。
但是,我经常在物理方面做一些事情,我需要使用 3D 向量进行快速数学运算。而且我没有找到任何方便的方法如何在 Java 中实现性能高效和可读性(C++ 结构,如宏、重载运算符、结构和通过引用传递变量是非常有用的工具)。
例如中心力场中质量粒子的跳跃式积分器。在 C++ 中,我可以做这样的事情(使用 float3 类型的重载运算符):
float ir2 = 1.0f/dot(vec_pos,vec_pos);
float ir = sqrt(ir2);
float3 vec_G = -vec_pos / (ir2*ir);
vec_v += vec_G*dt;
vec_pos += vec_v*dt;
Java 中的可读代码如下所示:
float ir2 = 1.0f/vec_pos.mag2();
float ir = sqrt(ir2);
float3 vec_G = vec_pos.mult( -ir2*ir);
vec_v .addLocal( vec_G.multLocal( dt ) );
vec_pos .addLocal( vec_v.mult ( dt ) );
这对性能不是很好,因为它将新对象分配为临时变量,其中“本地”方法无法使用。我可以通过为 fused-multiply-add 定义新方法来优化它,例如:
float ir2 = 1.0f/vec_pos.mag2();
float ir = sqrt(ir2);
float3 vec_G = vec_pos.mult( -ir2*ir);
vec_v .addLocal_vec_times_scalar( vec_G, dt );
vec_pos .addLocal_vec_times_scalar( vec_v, dt );
但是用float3向量为算术运算的所有可能组合定义专门的方法不是很方便……比如:
float3.addLocal_vec1_times_vec2_times_scalar()
另一种避免动态分配临时对象的策略是将临时变量定义为一些静态全局变量(这不是很好的编码风格)或封闭类的属性,例如:
class asteroide{
// state variables
float3 vec_pos;
float3 vec_v;
// temporary variables
float3 vec_G,vec_dpos;
void update_leapfrog(float dt){
float ir2 = 1.0f/vec_pos.mag2();
float ir = sqrt(ir2);
vec_G .set_mult( vec_pos, -ir2*ir );
vec_v .addLocal( vec_G.multLocal( dt ) );
dpos .set_mult( vec_v, dt );
vec_pos .addLocal( dpos );
}
}
在这两种情况下,都有取消引用指向此对象的指针的性能成本。它还使小行星天体消耗更多内存。
还有调用对象方法的性能损失(即使我尝试将它们设为“最终”和“静态”,以便 JIT 可以有效地内联它们)。根据我的测试,使用 float3.mult() 比仅乘以 3 个浮点数慢 2-3 倍。
所以我经常最终只使用浮点数编写复杂的向量代数计算,以避免这种性能损失。 :((( 但是它根本不可读。以这种方式进行刚体动力学和空气动力学计算是一件很痛苦的事情。它和 40 年前的 Fortran77 程序一样糟糕!!!! (只是为了好奇,请参阅例如 Xfoil http://web.mit.edu/drela/Public/web/xfoil/ 的代码)
你推荐什么策略在 Java 中进行向量数学,既高效又方便(~可读)?
【问题讨论】:
-
@Alan,不,这不是关于性能的问题,这是关于语法的问题。 OP 想用 Java 编写数学表达式,看起来就像他在纸上写的一样。
-
@James,更准确地说:这是一个关于性能的问题,也是一个语法问题。然而,我承认,我可能过于强调前者而不是后者。
-
这是关于妥协:如果我不想写出可读性好的向量数学性能很糟糕。
-
@ProkopHapala,这就是问题所在:在我看来,你可以用 Java 编写 a) 快速、b) 可读和 c) 的矩阵代码......问题是你只能得到选择两个。我通常要么用浮点数编写它,要么根据需要多少向量数学来获取我可以使用的性能最好的矩阵库。无论哪种方式,我都接受丑陋的矩阵数学代码(与 matlab/octave 相比)并彻底评论它。我玩过的另一种方法是在 C/C++ 中编写足够大的矩阵位并使用 JNI 调用。
标签: java performance math game-physics