I implemented and bench marked the following functions in c and java using the following code. For c, I'm getting about 1.688852 seconds while for java, it only takes like 0.355038 seconds. Even if I remove the sqrt
function, inline the code manually or change function signature to accept 6 double
coordinates (to avoid accessing via pointers) for c time lapsed doesn't improve much.
I'm compiling the c program like cc -O2 main.c -lm
. For java, I'm running the application in intellij idea with the default jvm options (java 8, openjdk).
c:
#include <math.h>
#include <stdio.h>
#include <time.h>
typedef struct point3d
{
double x;
double y;
double z;
} point3d_t;
double distance(point3d_t *from, point3d_t *to);
int main(int argc, char const *argv[])
{
point3d_t from = {.x = 2.3, .y = 3.45, .z = 4.56};
point3d_t to = {.x = 5.678, .y = 3.45, .z = -9.0781};
double time = 0.0;
int count = 10000000;
for (size_t i = 0; i < count; i++)
{
clock_t tic = clock();
double d = distance(&from, &to);
clock_t toc = clock();
time += ((double) (toc - tic) / CLOCKS_PER_SEC);
}
printf("Elapsed: %f seconds\n", time);
return 0;
}
double distance(point3d_t *from, point3d_t *to)
{
double dx = to->x - from->x;
double dy = to->y - from->y;
double dz = to->z - from->z;
double d2 = (dx * dx) + (dy * dy) + (dz + dz);
return sqrt(d2);
}
java:
public class App
{
static Random rnd = new Random();
public static void main( String[] args )
{
var sw = new StopWatch();
var time = 0.0;
var count = 10000000;
for (int i = 0; i < count; i++) {
var from = Vector3D.of(rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble());
var to = Vector3D.of(rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble());
sw.start();
var dist = distance(from, to);
sw.stop();
time += sw.getTime(TimeUnit.NANOSECONDS);
sw.reset();
}
System.out.printf("Time: %f seconds\n", time / 1e09);
}
public static double distance(Vector3D from, Vector3D to) {
var dx = to.getX() - from.getX();
var dy = to.getY() - from.getY();
var dz = to.getZ() - from.getZ();
return Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
}
}
My objective is to understand why the c program is slower and get it to work faster than the java program.
EDIT: I'm using random values in the java program to try and make sure jvm doesn't do anything funny like caching the result and sidestep computations altogether.
EDIT: Updating the two snippets for c to use clock_gettime()
, to clock the time taken for all the loops rather than the method call and also to not toss the result from the method call:
#include <math.h>
#include <stdio.h>
#include <time.h>
typedef struct point3d
{
double x;
double y;
double z;
} point3d_t;
double distance(point3d_t *from, point3d_t *to);
int main(int argc, char const *argv[])
{
point3d_t from = {.x = 2.3, .y = 3.45, .z = 4.56};
point3d_t to = {.x = 5.678, .y = 3.45, .z = -9.0781};
struct timespec fs;
struct timespec ts;
long time = 0;
int count = 10000000;
double dist = 0;
clock_gettime(CLOCK_REALTIME, &fs);
for (size_t i = 0; i < count; i++)
{
dist = distance(&from, &to);
}
clock_gettime(CLOCK_REALTIME, &ts);
time = ts.tv_nsec - fs.tv_nsec;
if (dist == 0.001)
{
printf("hello\n");
}
printf("Elapsed: %f sec\n", (double) time / 1e9);
return 0;
}
double distance(point3d_t *from, point3d_t *to)
{
double dx = to->x - from->x;
double dy = to->y - from->y;
double dz = to->z - from->z;
double d2 = (dx * dx) + (dy * dy) + (dz + dz);
return sqrt(d2);
}
java:
public class App
{
static Random rnd = new Random();
public static void main( String[] args )
{
var from = Vector3D.of(rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble());
var to = Vector3D.of(rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble());
var time = 0.0;
var count = 10000000;
double dist = 0.0;
var start = System.nanoTime();
for (int i = 0; i < count; i++) {
dist = distance(from, to);
}
var end = System.nanoTime();
time = end - start;
if (dist == rnd.nextDouble()) {
System.out.printf("hello! %f\n", dist);
}
dist = dist + 1;
System.out.printf("Time: %f sec\n", (double) time / 1e9);
System.out.printf("Yohoo! %f\n", dist);
}
public static double distance(Vector3D from, Vector3D to) {
var dx= to.getX() - from.getX();
var dy = to.getY() - from.getY();
var dz = to.getZ() - from.getZ();
return Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
}
}
Compiling c code using gcc -Wall -std=gnu99 -O2 main.c -lm
. The results now are 0.06323 seconds for c code and 0.006325 seconds for java.
EDIT: As Jérôme Richard and Peter Cordes pointed out my bench marking is just flawed, not to mention I was taking the sqrt of a negative number in the c version. So, as soon as I compiled the c program with -fno-math-errno
, it clocked 0 seconds. I compiled c program like gcc -O2 -std=gnu99 main.c -lm
. Now the c program is clocking effectively zero seconds (271 ns) while java clocking 0.007217 seconds. Everything's in order :)
Below is the final code:
c:
#include <math.h>
#include <stdio.h>
#include <time.h>
typedef struct point3d
{
double x;
double y;
double z;
} point3d_t;
double distance(point3d_t *from, point3d_t *to);
int main(int argc, char const *argv[])
{
point3d_t from = {.x = 2.3, .y = 3.45, .z = 4.56};
point3d_t to = {.x = 5.678, .y = 3.45, .z = -9.0781};
struct timespec fs;
struct timespec ts;
long time = 0;
int count = 10000000;
double dist = 0;
clock_gettime(CLOCK_REALTIME, &fs);
for (size_t i = 0; i < count; i++)
{
dist = distance(&from, &to);
}
clock_gettime(CLOCK_REALTIME, &ts);
time = ts.tv_nsec - fs.tv_nsec;
printf("hello %f \n", dist);
printf("Elapsed: %f ns\n", (double) time);
printf("Elapsed: %f sec\n", (double) time / 1e9);
return 0;
}
double distance(point3d_t *from, point3d_t *to)
{
double dx = (to->x) - (from->x);
double dy = (to->y) - (from->y);
double dz = (to->z) - (from->z);
double d2 = (dx * dx) + (dy * dy) + (dz * dz);
return sqrt(d2);
}
java:
public class App
{
static Random rnd = new Random();
public static void main( String[] args )
{
var from = Vector3D.of(2.3, 3.45, 4.56);
var to = Vector3D.of(5.678, 3.45, -9.0781);
var time = 0.0;
var count = 10000000;
double dist = 0.0;
var start = System.nanoTime();
for (int i = 0; i < count; i++) {
dist = distance(from, to);
}
var end = System.nanoTime();
time = end - start;
System.out.printf("Yohoo! %f\n", dist);
System.out.printf("Time: %f ns\n", (double) time / 1e9);
}
public static double distance(Vector3D from, Vector3D to) {
var dx = to.getX() - from.getX();
var dy = to.getY() - from.getY();
var dz = to.getZ() - from.getZ();
var d2 = (dx * dx) + (dy * dy) + (dz * dz);
return Math.sqrt(d2);
}
}