So I was recently writing some code for my robotics class, and I wrote this code:
/*
alpha: repulsion coefficient
gamma: attraction coefficient
x0x, x0y: position of robot 0
xjx, xjy: position of robot j
r0, rj: robot radii
dSafe: safe distance
dFar: "too far" distance
*/
Vector2 getFollowerAttraction(double alpha, double gamma,
double x0x, double x0y, double xjx, double xjy, double r0, double rj,
double dSafe, double dFar) {
// Create the return struct
Vector2 fa;
// Calculate the distance between the center of robot j to 0
double sx = x0x - xjx;
double sy = x0y - xjy;
double sm = sqrt(sx*sx + sy*sy);
// Subtract the radii of the robots
double d = sm - (r0 + rj);
// Calculate the vector conversion factor
double ka;
if (d < dSafe) {
ka = -alpha / (d*d * sm);
} else if (d < dFar) {
fa.x = 0;
fa.y = 0;
return fa;
} else {
ka = gamma * d*d / sm;
}
// Calculate the vector of the force
fa.x = ka * sx;
fa.y = ka * sy;
return fa;
}
Vector2 getFollowerAttraction() {
Pose &x0 = pose[0];
Pose &xj = pose[ID];
return getFollowerAttraction(REPULSION_CONSTANT_ALPHA,
ATTRACTION_CONSTANT_GAMMA, x0.x, x0.y, xj.x, xj.y, ROBOT_RADIUS_M,
ROBOT_RADIUS_M, SAFE_DISTANCE_M, FAR_DISTANCE_M);
}
I figured that having the option to override the constants if necessary by calling the first form was a nice thing to have. But I was concerned that adding this ability would cost me performance. Putting 640 bits of arguments on the stack seemed a bit overkill if they weren't needed. So I decided to do a bit of an experiment, and I am very pleased with the results. I wrote a simple C++ file called test.cpp:
const double A = 0;
const double B = 1;
const double C = 2;
const double D = 3;
const double E = 4;
const double F = 5;
const double G = 6;
const double H = 7;
const double I = 8;
const double J = 9;
double add(double a, double b, double c, double d, double e, double f,
double g, double h, double i, double j) {
return a + b + c + d + e + f + g + h + i + j;
}
double add() {
return add(A, B, C, D, E, F, G, H, I, J);
}
int main() {
return (int)add();
}
I tested it:
0 ✓ ntd5@ntd5-mbpro ~
% g++ test.cpp -o test -O2
0 ✓ ntd5@ntd5-mbpro ~
% ./test
45 ✗ ntd5@ntd5-mbpro ~
% g++ test.cpp -S -o test.s -O2
And this was what I got for the assembly (test.s):
.file "test.cpp"
.text
.p2align 4,,15
.globl _Z3adddddddddddd
.type _Z3adddddddddddd, @function
_Z3adddddddddddd:
.LFB0:
.cfi_startproc
addsd %xmm1, %xmm0
addsd %xmm2, %xmm0
addsd %xmm3, %xmm0
addsd %xmm4, %xmm0
addsd %xmm5, %xmm0
addsd %xmm6, %xmm0
addsd %xmm7, %xmm0
addsd 8(%rsp), %xmm0
addsd 16(%rsp), %xmm0
ret
.cfi_endproc
.LFE0:
.size _Z3adddddddddddd, .-_Z3adddddddddddd
.p2align 4,,15
.globl _Z3addv
.type _Z3addv, @function
_Z3addv:
.LFB1:
.cfi_startproc
movsd .LC0(%rip), %xmm0
ret
.cfi_endproc
.LFE1:
.size _Z3addv, .-_Z3addv
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
movl $45, %eax
ret
.cfi_endproc
.LFE2:
.size main, .-main
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LC0:
.long 0
.long 1078362112
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
As you can see below _Z3addv
, the constants got applied into the function.
One can imagine that you would get similar optimization in my robotics code.
Yay!