3

In general, I like programming in Java much more than C++ mostly because linking of libraries is much easier (no "dependency hell") and because there are great packages with a lot of functionality out of the box. I also like java tools like jMonkey and Processing.

However, I very often do something with physics where I need fast math with 3D vectors. And I didn't find any convenient way how to do it in Java both performance efficient and readable ( C++ constructs like macros, overloaded operators, structs, and passing variables by reference are very helpful tools for this purpose ).

For example leapfrog integrator of a mass particle in central forcefield. In C++ I can make something like this ( using overloaded operators for type 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; 

readable code in Java would look like:

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 ) );

which is not very good for performance since it allocates new objects as temporary variabales where "Local" method is not possible to use. I can optimize it by defining new methods for fused-multiply-add like:

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 );

But it is not very convenient to define specialized method for all possible combinations of arithmetic operations with float3 vector ... like:

  float3.addLocal_vec1_times_vec2_times_scalar() 

An other strategy how to avoid allocation of temporary objects on-the-fly is to define this temporary variables once as some static global variables (which is not nice coding style) or as properties of enclosing class like:

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 );
   }
}

In both cases there is performance cost for dereferencing pointers to this objects. It also make asteroide object more memory consuming.

There is also performance penalty for calling object methods (even if I try to make them "final" and "static" so JIT can inline them effectively ). According to my test using float3.mult() is 2-3x slower than just multiplication of 3 float.

So I often end up writing complex vector algebra computations using just float , to avoid this performance penalties. :((( But than it is not readable at all. Doing rigid body dynamics and aerodynamics computation in this way is pain in the ass. It is as bad as Fortran77 programs 40 years ago !!!! ( just for curiosity see eg. code of Xfoil http://web.mit.edu/drela/Public/web/xfoil/ )

What strategy you recommend for doing vector math in Java both performance efficient and convenient (~readable)?

Prokop Hapala
  • 2,424
  • 2
  • 30
  • 59
  • possible duplicate of [Performance of Java matrix math libraries?](http://stackoverflow.com/questions/529457/performance-of-java-matrix-math-libraries) – Alan Oct 15 '14 at 19:35
  • @Alan, no this is not a question about performance, this is a question about syntax. The OP wants to write mathematical expressions in Java that look like what he would write on paper. – Solomon Slow Oct 15 '14 at 19:38
  • @James, more accurately: this is a question about performance, but also one of syntax. I will concede, however, that I may have placed too much emphasis on the former than the latter. – Alan Oct 15 '14 at 19:42
  • It's about the compromise: If I wan't to write nice readable vector math performance sucks. – Prokop Hapala Oct 15 '14 at 19:45
  • @ProkopHapala, that's the rub: it seems to me that you can write matrix code that is a) fast, b) readable, and c) in Java... The problem is that you only get to pick two. I usually either write it with floats or grab the best performing matrix library that I can use depending on how much vector math is needed. Either way I resign myself to ugly matrix math code (in comparison to matlab/octave) and comment it thoroughly. The other approach I have played with is to write sufficiently large matrix bits in C/C++ and call using JNI. – Alan Oct 15 '14 at 20:51

1 Answers1

0

Maybe not a real answer, but way too long for a comment.

How did you measure the performance? All optimizations need a while; if your measurement took less than a few seconds, then just forget it.

In theory, JIT should be capable of optimizing away the needless allocation.

Concerning ugliness: Sure, with names like addLocal_vec_times_scalar it must be ugly. Something like addProduct would do.

There is also performance penalty for calling object methods (even if I try to make them "final" and "static" so JIT can inline them effectively )

This is not needed, as JIT can see if the method was overriden somewhere.

What strategy you recommend for doing vector math in Java both performance efficient and convenient (~readable)?

Don't try to make it look like C. Define a few methods like fused multiply and ignore rare cases. If you're using names like float3.addLocal_vec1_times_vec2_times_scalar, it simply must be ugly. What's wrong with

 vec1.addProduct(vec2, vec3, someScalar)
maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • It is not about ugly names, it's about generality (reusability) of the code. the methods are just to specialized. I don't like to write again and again almost the same code for each combination of arguments. – Prokop Hapala Oct 15 '14 at 22:05
  • @ProkopHapala I understand, but there are not so many common argument combinations, you'll use maybe 5-10 of them all the time and ignore the inefficiencies with the others (if any; I can't think of more than 10 useful combinations). If your vectors were large, then you could use something smarter, but with float3 there's no room left. – maaartinus Oct 15 '14 at 22:40