Sunday, February 20, 2011

Units of Measure: Doing Physics in .net Part I

Having just started getting into C#, I can already say that it’s a pleasure to work with – especially when used with its tightly coupled IDE, Visual Studio. Of course, being a physics/astronomy/computer science geek, I got straight to work doing some projectile physics in C# to see how it turned out. To get myself started on this blog, I’m going to write a couple of posts about doing physics in .net.

For part one, I’ll do a brief intro into F#’s units of measure.

So, when I got started on this C# projectile stuff, it started looking a little like this:

namespace CsPhysicsDemo
{
    class Projectile
    {
        public const double g = -9.80;
        public double xi;
        public double yi;
        public double vxi;
        public double vyi;

        public double xf(double t)
        {
            return xi + vxi * t;
        }

        public double yf(double t)
        {
            return yi + vyi * t + 0.5 * Projectile.g * t;
        }
    }
}

Nice. The variables stand for “x initial,” “velocity x initial,” etc. This compiles and works fine – but guess what. There’s a mistake in there. Can you spot it? It’s not easy. the yf() function is supposed to return the vertical position of the projectile at a given time – instead it returns its velocity, plus its initial displacement. Which, of course, doesn’t make sense. The problem here isn’t just that we forgot to square t, but that – despite the strongly typed nature of C# – there’s no type checking for what kind of double we’ve created in this math operation.

Enter F#’s units of measure:

#light

namespace PhysicsDemo

module Physics =
    [<Measure>] type m
    [<Measure>] type s

    let xf (xi : float<m>) (v : float<m/s>) (a : float<m/s^2>) (t : float<s>) =
        xi + v * t + 0.5 * a * t * t

If you don’t already know a little bit about F#, I urge you to go take a look at Chris Smith's “F# in 20 Minutes" for a run-down of the language.

So there’s our projectile math, made a little more general. Have I written it right this time? Are spacecraft going to go crashing into planets when this code is executed? Take a look:

fsReturnType1

Just from hovering over the function name with the mouse, we know that this function’s return value is in meters. There’s also no unit errors in the math, or this would happen:

fsUnitError1

You can see that the + operator is underlined in red: because you can’t add two values with different units together. On the left side, you have m + (m/s * s), or m + m, or m. On the right, you’ve got (m/s^2 * s), or m/s. This comes in handy in all kinds of ways:

fsTypeMismatch

vi and vf were supposed to be in m/s (since they came from a velocity function) but appear to be in meters. What went wrong?

fsReturnType2

Of course, my velocity function is wrong. There’s clearly some benefit for using F# for physical math – but how does that help? Sure it looks cool in a demonstration, but how would a person actually get anything done this way? It’s not like it makes sense to port everything over to F#. We’ll start an F# physics library in Part II, which is not at all as hard as it sounds.

6 comments:

  1. I've read parts 1 and 2 of F# in 20 minutes, and I still don't recognize the constructs you are using here. Part 3 was mentioned in part 2, but doesn't seem to exist.

    ReplyDelete