The food coop kicks back in to gear after being postponed from the day before, and a lot of simplification occurs to some code making it much easier to understand.

Food co-op creative maths

What with yesterday’s delay, the food co-op got back in to the swing of things today on Thursday. Apparently it wasn’t the weather that stopped the truck from arriving yesterday, but was instead a genuine break-down of the vehicle for other reasons.

Des seems to like putting me on to food items that need weighing, which has something to do with the running tally that I keep in my head during the course of things. Normally we would take the 29 10kg crates of tomatoes and needing 356 packs, and figure out that:

\frac{290}{356} = 0.81

resulting in us wanting 800g of tomatoes in each pack. But I found a much easier solution. While weighing up 800 grams at a time and tracking that we were under by 150 on this pack, over by 100 on another leaving us 50 to play with, and over by 50 on the next bring us back to an even balance of things, I also did some rough division in my head for the number of packs divided by the crates we had, which gives us:

\frac{356}{290} = 12.3

So we’ll be wanting 13 packs from each crate of tomatoes, which is much easier to achieve without such detailed weighing. Since the crates invariably contained 14 sets of tomatoes still on their vines, it was a simple case of throwing the occasional extra tomato in with each pack and job’s done.

Sure, math can solve problems and can be quite useful, but taking things a bit further can help us to be lazier more efficient. Sometimes a bit of creative thinking can go a long way too.

Simplifying code

It all started off last year as the following spaghetti code from FORTRAN for working out information about an aircraft at different speeds:

   20 V=V+DELV
      IF(V.LT.VS1) GO TO 20
   21 RC1=RC
      VH=V/VMINS
      RSH=.25*(VH**4+3.)/VH
      RS=RSH*RSMIN
      VT=V/VPROP
      T2=SQRT(1.+0.23271*VT**3)
      ETA=0.92264*VT*((1.+T2)**T1-(T2-1.)**T1)*.85
      RC=RCSTAR*ETA-RS
      IF (RC.GT.RCMAX)RCMAX=RC
      RC2=RC
      IF(RC.LE.0.) GO TO 23
      REC=SIG*V*C*9324./RMU
      PRINT 103,V,RC,ETA,RS,REC
  103 FORMAT(4X,F6.1,7X,F6.1,7X,F6.4,7X,F6.1,6X,E10.3)
      IF(ISTAL.EQ.1) GO TO 22
      IF(IMAX.EQ.1) GO TO 24
      GO TO 20
   22 CONTINUE
      V=0.
      ISTAL=0
      GO TO 20
   23 CONTINUE
      IMAX=1
      V=V-DELV*RC2/(RC2-RC1)
      GO TO 21
   24 CONTINUE

which is horrible code, but that’s the best that could be expected several decades ago.

Making improvements to it when translating it to JavaScript can help to highlight structure of the code, and moving some parts out to separate functions helps to make things easier to understand:

do {
    rc_prev = stats.rc || rc;
    stats = calculateStats(v, data);
    if (stats.rc > 0) {
        calculated.push(stats);
        if (!imax) {
            v = nextDeltaAirspeed_alt(v, vel_step, data.vs1);
        }
    } else {
        v = finalAirspeed(v, vel_step, stats.rc, rc_prev);
        imax = true;
    }
} while (imax === false || stats.rc <= 0);

and even though we can more clearly see what’s happening, it’s still difficult to understand what is going on and why.

Effectively the imax value is used to figure out if we’ve reached the maximum achievable velocity, so that we can loop through one more time to find a final airspeed.

I ended up pulling things apart by removing the else clause, and realised that three main things are happening in the loop. First an initial airspeed is being calculated, then the airspeed is being gradually increased until no more lift is available, and lastly the final airspeed is being worked out.

Because the loop has only one main purpose, the other parts dealing with the initial and final airspeeds can and should be extracted out. By separating these from each other we can achieve a greater understanding of the code.

So by tweezing things apart we now end up with the following:

stats = calculateStats(v, data);

do {
    calculated.push(stats);
    v = nextDeltaAirspeed_alt(v, vel_step, data.vs1);
    stats = calculateStats(v, data);
} while (stats.rc > 0);

v = finalAirspeed(calculated[calculated.length - 1], stats);
stats = calculateStats(v, data);
calculated.push(stats);

which is a lot easier to understand than anything we had before.

Advertisements