Genie: Write Python-like code that runs as fast as pure C

There is an article on the Postabon Blog titled “Make Lisp 15x faster than Python or 4x faster than Java.” In his benchmark, which is a tightly nested loop doing some trigonometric calculations, he achieves speed similar to Java with unoptimized Lisp and a 4X speed increase over that with some Lisp optimizations. He also compares it with Python which is silly because Python’s slowness is a known and insurmountable problem with the language.

I’ve been looking for a programming language with some of the feel of Python but with static, inferred typing. There are a couple, but Genie caught my eye so I wrote his algorithm in Genie. Basically, the differences between Genie and Python I noticed in porting the code are that functions need type declarations (something I have yet to see inferred in any statically typed language) and that variables are initialized with the “var” keyword. Genie does away with Python’s use of the colon, which is redundant, and instead uses it for type declarations.

Here is the new code.

[indent=4]
uses
    GLib
 
def radians(n : double) : double
    return n * 0.0174532925
 
def distance(latA : double, lngA : double, latB : double, lngB : double) : double
    var radius = 6371.0
    var latAr = radians(latA)
    var lngAr = radians(lngA)
    var latBr = radians(latB)
    var lngBr = radians(lngB)
 
    var deltaLat = latBr - latAr
    var deltaLng = lngBr - lngAr
 
    return radius * 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(deltaLat/2),2.0) \
        + Math.cos(latAr) * Math.cos(latBr) * (Math.pow(Math.sin(deltaLng/2),2.0))))
 
def bench()
    var increment = 2.5
 
    var latA = -90.0
    while(latA <= 90.0)
        var lngA = -180.0
        while(lngA <= 180.0)
            var latB = -90.0
            while(latB <= 90.0)
                var lngB = -180.0
                while(lngB <= 180.0)
                    distance(latA, lngA, latB, lngB)
                    lngB = lngB + increment
                latB = latB + increment
            lngA = lngA + increment
        latA = latA + increment
 
init
    bench()

This code runs on my laptop in about 35 seconds, which as far as I can tell from the blog post, is about as fast as the optimized Lisp. Of course, Genie is translating the code into pure C, and then compiling it to an executable. Syntax is a matter of personal taste, and I like the way Genie works. Since it compiles to a pure binary, there is no runtime. It leverages existing C libraries, using GLib objects as its native object system. The C API is universal and Genie can emit C header files too, so I could see myself writing Genie code that integrated with almost any software development platform.

For comparison, here is the somewhat verbose C code generated by valac, the Genie / Vala compiler.

#include <glib.h>
#include <glib-object.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
 
double radians (double n);
double distance (double latA, double lngA, double latB, double lngB);
void bench (void);
void _main (char** args, int args_length1);
 
double radians (double n) {
    double result;
    result = n * 0.0174532925;
    return result;
}
 
double distance (double latA, double lngA, double latB, double lngB) {
    double result;
    double radius;
    double latAr;
    double lngAr;
    double latBr;
    double lngBr;
    double deltaLat;
    double deltaLng;
    radius = 6371.0;
    latAr = radians (latA);
    lngAr = radians (lngA);
    latBr = radians (latB);
    lngBr = radians (lngB);
    deltaLat = latBr - latAr;
    deltaLng = lngBr - lngAr;
    result = (radius * 2) * asin (sqrt (pow (sin (deltaLat / 2), 2.0) + ((cos (latAr) * cos (latBr)) * pow (sin (deltaLng / 2), 2.0))));
    return result;
}
 
void bench (void) {
    double increment;
    double latA;
    increment = 2.5;
    latA = -90.0;
    while (TRUE) {
        double lngA;
        if (!(latA <= 90.0)) {
            break;
        }
        lngA = -180.0;
        while (TRUE) {
            double latB;
            if (!(lngA <= 180.0)) {
                break;
            }
            latB = -90.0;
            while (TRUE) {
                double lngB;
                if (!(latB <= 90.0)) {
                    break;
                }
                lngB = -180.0;
                while (TRUE) {
                    if (!(lngB <= 180.0)) {
                        break;
                    }
                    distance (latA, lngA, latB, lngB);
                    lngB = lngB + increment;
                }
                latB = latB + increment;
            }
            lngA = lngA + increment;
        }
        latA = latA + increment;
    }
}
 
void _main (char** args, int args_length1) {
    bench ();
}
 
int main (int argc, char ** argv) {
    g_type_init ();
    _main (argv, argc);
    return 0;
}

Post a Comment

Your email is never published nor shared. Required fields are marked *

Powered by WP Hashcash