ID:309703
 
In the most recent version of my ProcLib (which may or may not be visible, I don't remember), I have vector functions as #define statements, like so:
// this:
#define new_vec2(x, y) list(x, y)

#define vec2_add(u, v) new_vec2(u[1]+v[1], u[2]+v[2])
#define vec2_sub(u, v) new_vec2(u[1]-v[1], u[2]+v[2])

#define vec2_mag(u) sqrt(u[1]*u[1] + u[2]*u[2])

#define vec2_scale(u, s) new_vec2(u[1]*s, u[2]*s)
#define vec2_unit(u) vec2_scale(u, 1/vec2_mag(u))

// etc.

The problem I have with the above is that it's creating a new /list for every operation. Would it be better to instead have them calculate on vector u itself, instead of returning a (new) resultant vector?
// or this:
// (operations are made on the vector itself instead of making a new /vector datum)
vector
var comp[]
New() comp = args

proc
add(vector/v)
for(var/d in max(comp.len, v.comp.len))
comp[d] += v.comp[d]

scale(s)
for(var/d in comp.len)
comp[d] *= s

// etc.


With the first method, you can do multiple operations in just one line. For example, I have a gravity simulator. This is as much as I can remember off the top of my head, but I think it's a good example.
// src and m are objects with mass
// pos (position) is a (vector, /list) coordinate
var d[] = vec2_sub(m.pos, pos) // displacement vector
var r = vec2_mag(d) // distance between them
vel = vec2_add(vel, vec2_scale(d, grav_const * m.mass / r / r / r))

This makes a total of 3 /lists just to change one vector. One as a result of vec2_sub, another as a result of vec2_scale, and the last as a result of vec2_add. vel is a whole new /list in the end.

To do this with the second method:
var vector/d = new(m.pos.comp.Copy())
d.sub(pos)

var r = d.mag()
d.scale(grav_const * m.mass / r / r / r)

vel.add(d)

This makes only one vector, d for displacement, which is modified and eventually added to vel.



Which way is best? Is there even a significant difference? Can we have native vector support?
I'd expect that native vectors would be treated like lists so I don't think the performance would be much different.

The second code snippet is pretty simple. I'd just give vectors a copy proc so you can say m.pos.copy() instead of new(m.pos.comp.Copy()).

You could also add procs that operate on vectors in addition to procs that belong to vector objects. The catch is that these procs have to return new vector objects, but sometimes that's what you want:

// instead of doing this:
var/vector/d = new(m.pos.comp.Copy())
d.sub(pos)

// you can do:
var/vector/d = vec_sub(m.pos, pos)

This would make your second snippet even simpler.

I'm not sure how much of a difference this all makes. If one method takes twice as much time you might consider that significant, but these vector operations shouldn't be the bottleneck in your program anyway.
Ideally, I want to get the same performance from doing this:
vel_x += accel_x
vel_y += accel_y


as this:
vel += accel
// vel and accel are vectors
Unless adding vectors is the only thing your program does, you will not be able to detect the difference in performance between performing one addition operation or two.

With lists or vector objects it's not the math that's time consuming, it's the garbage collection when the intermediate objects go out of scope.