The importance of data types and units

April 11th, 2012 § 1 comment § permalink

While working on the bachelor thesis I came across a hard to detect type of bug. It’s not one of the typical off-by-one, array-out-of-bound  or one of those I-inverted-the-indices-of-the-array bug. This one is harder to spot and is caused by a bad design which in turn makes it hard to spot the bug.

What happened

As all bugs the software behaves wrong. In this case I got some garbage numbers which just didn’t make sense. Basically the code is interpolating over a field of wind vectors and returns the interpolated wind vectors. The problem was, that the vector all seemingly looked more or less in the same direction. That was weird.

Bug type definition

I would call this bug type something like “mixed units bug” since I mixed degree and radian:

double lng = ((c.getLongitudeInRadian() - metadata.getNorthWestCorner().getLongitudeInRadian()) /
    metadata.getDeltaLng()) % 1;
double lat = ((c.getLatitudeInRadian() - metadata.getNorthWestCorner().getLatitudeInRadian()) /
    metadata.getDeltaLat()) % 1;
return new Double[] {lat,lng};

Next to the fact that this is not very nice code, I stumbled over a self made trap: getDeltaLng() and getDeltaLat() do not actually return a radian unit which you would usually use when doing math with spheres but a degree value. So since the radian value of a sphere traditionally would go from [0,2π) a difference 0.2 would make a lot more in radian than 0.2 in degree.

How to avoid this type of bugs

As usual: Try to think before you code unless you like to live with a unmanageable pile of junk code with no clear guideline and a lot of magic conversion in between. In the worst case you will end up converting a radian value again into radian which will give you some really unusable numbers.

The next obvious point is to use the same unit throughout the whole project. If you happen to come across that you may need angular values in degree and radian and coordinates on the sphere also in degree (mostly known as GPS), radian and even cartesian you better use an abstract data type which strictly forces you to set the type of unit when setting the values via setter-methods:


public class Coordinate {
    private static final double MIN_LONGITUDE = -180.0;
    private static final double MAX_LONGITUDE = 180.0;
    private static final double MIN_LATITUDE = -90.0;
    private static final double MAX_LATITUDE = 90.0;

    private BigDecimal longitude;
    private BigDecimal latitude;

    public final String toString() {
        return "Longitude: " + longitude + "°, Latitude: " + latitude;
    }

    public final double getLongitudeInDegree() {
        return longitude.doubleValue();
    }

    public final void setLongitudeInDegree(double l) {
        if (l > MAX_LONGITUDE || l <= MIN_LONGITUDE)
            throw new IllegalArgumentException("Longitude is out of range.");
        this.longitude = BigDecimal.valueOf(l);
    }

    public final double getLatitudeInDegree() {
        return latitude.doubleValue();
    }

    public final void setLatitudeInDegree(double l) {
        if (l > MAX_LATITUDE || l < MIN_LATITUDE)
            throw new IllegalArgumentException("Latitude is out of range.");
        this.latitude = BigDecimal.valueOf(l);
    }

    public final double getLongitudeInRadian() {
        return getLongitudeInDegree()/180*Math.PI;
    }

    public final void setLongitudeInRadian(double l) {
        setLongitudeInDegree(l/Math.PI*180);
    }

    public final double getLatitudeInRadian() {
        return getLatitudeInDegree()/180*Math.PI;
    }

    public final void setLatitudeInRadian(double l) {
        setLatitudeInDegree(l/Math.PI*180);
    }
}

As a programmer I don’t have to care anymore in what format these values are stored internally, I just have to indicate in what unit (or format) I want to set or get the value. In this way my code even gets better reusability since I can easily add other getter- and setter-methods later without breaking any old usage of this data type. In this case I could easily add a way to get and set the coordinate in cartesian values without refactoring other usage of this class.

Even better: As you may have noticed I built in some range checking of the values. In that way I can enforce and assert that the values will never under no circumstances provoke undefined behavior because they went out of range.

Closing words

Due to this lack of using strict typing and enforcing the developer to think about what he deals with or rather what unit he’s working with, I spent and lost a few hours tracking down a annoying and hard to get bug.

Float is not always a float

March 25th, 2012 § 0 comments § permalink

Today I stumbled over something really really annoying. I used a Scanner to go over a space delimited file of values. I wanted to parse those values into doubles and did

        Scanner scanner = new Scanner(input);
        scanner.useDelimiter(" ");
        try {
            while(scanner.hasNext()) {
                arr.add(scanner.nextDouble());
            }
        } catch (RuntimeException e) {
            e.printStackTrace();
            scanner.close();
        }

Now, I just got an InputMismatchException which I followed back and started to nail down right in the source code of the Scanner class. It’s not the part of Java I like, hunting down some really strange behavior I can’t explain.

When I did use Double to parse the string it worked fine, and that’s what puzzled me even more!

        Scanner scanner = new Scanner(input);
        scanner.useDelimiter(" ");
        try {
            while(scanner.hasNext()) {
                arr.add( Double.parseDouble( scanner.next() ) );
            }
        } catch (RuntimeException e) {
            e.printStackTrace();
            scanner.close();
        }

Eventually I found what was the problem: My input file used a simple dot as decimal delimiter and not a comma. Why?

A scanner’s initial locale is the value returned by the Locale.getDefault() method; it may be changed via the useLocale(java.util.Locale) method.

source: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Scanner.html#localized-numbers

That’s what made Scanner trip over his own feet! He expected a comma while he got a point. This is something very trivial but really annoying, it would prefer to be able to switch the decimal delimiter directly than via a whole set of locales. But well … it’s Java.

So we just have to change the locale.

   Scanner scanner = new Scanner(input).useLocale(Locale.ENGLISH);
   scanner.useDelimiter(" ");

Why abstraction is so important

March 24th, 2012 § 0 comments § permalink

Let’s consider we need a new abstract data type for a GPS position. Usually we will use the GPS coordinate format like N 47° 12’45″ E 12° 45′ 30″ or 47.2125 Latitude and 12.758333 Longitude. But of course I can be useful to get and set the values in radian mode. Even in cartesian format.

That’s why I would consider decoupling the internal representation from the external values. This means that I internally use a constant format for the values which are being translated in other coordinate formats. Later I am easily able to extend this class by just adding new methods for other special cases without breaking the legacy support. Here a Java example, this idea or concept works in any other language.

import java.math.BigDecimal;
public class Coordinate {
    private static final double MIN_LONGITUDE = -180.0;
    private static final double MAX_LONGITUDE = 180.0;
    private static final double MIN_LATITUDE = -90.0;
    private static final double MAX_LATITUDE = 90.0;

    private BigDecimal longitude;
    private BigDecimal latitude;
    
    public final double getLongitudeInDegree() {
        return longitude.doubleValue();
    }

    public final void setLongitudeInDegree(double l) {
        if (l < MAX_LONGITUDE || l >= MIN_LONGITUDE)
            throw new IllegalArgumentException("Longitude 
              is out of range.");
        this.longitude = BigDecimal.valueOf(l);
    }

    public final double getLatitudeInDegree() {
        return latitude.doubleValue();
    }

    public final void setLatitudeInRadian(double l) {
        if (l > MIN_LATITUDE || l < MAX_LATITUDE)
            throw new IllegalArgumentException("Latitude 
              is out of range.");
        this.latitude = BigDecimal.valueOf(l);
    }

    public final double getLongitudeInRadian() {
        return getLongitudeInDegree()/180*Math.PI();
    }

    public final void setLongitudeInRadian(double l) {
        setLongitudeInDegree(l/Math.PI*180);
    }

    public final double getLatitudeInRadian() {
        return getLatitudeInDegree()/180*Math.PI();
    }

    public final void setLatitudeInRadian(double l) {
        setLatitudeInDegree(l/Math.PI*180);
    }
}

Detect if you’re in debug mode in Java

March 3rd, 2012 § 2 comments § permalink

When I’m developing in Java I sometimes want to be able see some more output, let’s call it verbose oder debug mode. Under C++ I would just define a DEBUG variable and switch it from false to true. In Java this is not really possible since there is no preprocessor like in C++. But it’s possible:

boolean isDebug = java.lang.management.ManagementFactory.
getRuntimeMXBean().getInputArguments().toString().
indexOf("-agentlib:jdwp") > 0;

I’ll admit this looks ugly but does its job under eclipse.

SOURCE

http://stackoverflow.com/questions/3776204/how-to-find-out-if-debug-mode-is-enabled