Fortran Re-engineering: Debt repayment schedule (i)

One of the nice things about Fortran is that most compilers will compile just about any legacy Fortran code. Take for example the following program which computes the amount of a debt with interest compounded, the amount of annual instalment repayments,  and a repayment schedule. This is a commercial loan which allows a sum to be borrowed without repayment of principal or interest for a fixed period of time. Repayment then occurs in instalments over several more years.

C     DEBT REPAYMENT SCHEDULE
      INTEGER YEAR, BDATE
      REAL I, INT, INTAMT
 10   READ(5,1,END=50) AMT,I,N,K,BDATE
 1    FORMAT(F7.0,F2.2,2I3,I4)
      WRITE(6,2) BDATE,AMT,I,N
 2    FORMAT('1',18X,'REPAYMENT SCHEDULE'/5X,' LOAN DATE ',
     1'DEC. 31, ',I4,5X,'AMOUNT BORROWED ',F8.0,' INTEREST RATE ',
     2F4.2/5X,'REPAYMENT TO BEGIN AFTER ',I3,' YEARS'//
     414X,'REPAYMENT',16X,'PRINCIPAL'/5X,'YEAR',7X,'AMOUNT',4X,
     5'INTEREST',5X,'REDUCTION BALANCE')
      CMPAMT=AMT*(1.+I)**N
      WRITE(6,3) CMPAMT
 3    FORMAT(53X,F8.0)
      PMTAMT=CMPAMT/(((1.+I)**K-1.)/(I*(1.+I)**K))
      DO 15 J=1,K
      YEAR=BDATE+N+J
      INT=CMPAMT*I
      BALRD=PMTAMT-INT
      CMPAMT=CMPAMT-BALRD
 15   WRITE(6,4) YEAR,PMTAMT,INT,BALRD,CMPAMT
 4    FORMAT(5X,I4,6X,F8.0,3X,F8.0,5X,F8.0,6X,F8.0)
      INTAMT=PMTAMT*FLOAT(K)-AMT
      WRITE(6,5) INTAMT
 5    FORMAT(/5X,'TOTAL INTEREST CHARGE ',F8.0)
      GOTO 10
 50   STOP
      END

Here is the input to the program:

0100000100050041978

This uses the following formula to calculate the future amount, A:

A = P(1+r)^n

where P is the amount originally borrowed, r is the interest rate, and n the number of periods before repayment begins. For the example given, the balance before repayment is therefore 100000*(1+0.1)^5 = $161,051.

This amount must be repaid in installments over the agreed-upon period. As payments are made, the unpaid amount continues to accrue interest, therefore computation of the amount which will repay principal and all interest in even installments is calculated using the formula:

where A is the amount to be repaid, r is the interest rate, and n the number of installment payments. This makes the assumption that the installment payments will be made at the end of each repayment year.

And the corresponding output:

The re-engineering of code like this (albeit small) is not that difficult, due to the lack of unstructured jumps in the code.

 

 

 

 

 

A lack of problem solving in CS education

Of all the science-like subjects, computer science is likely one of the youngest, although the term “computer science” is somewhat of a misnomer because computing is not a science, or an engineering (the hardware side might be). Programming is a craft that has in many ways dramatically changed over the years since its inception in the mid 1950s. Software systems are complex, and data is used in behemoth proportions. Yet the one thing that has not evolved is the way we teach programming. I think programming incorporates two core tasks, algorithm design and coding (lets leave testing etc to the wayside). The craft of programming is not that hard to learn, and the way we teach that has not really changed in the last 50 years (since the onset of structured programming). The languages have changed somewhat, but the basic ideas, constructs, and ideologies remain the same. That being said, programming is *not* for everyone. You have to have as much as zeal for it, as one would for a physical craft such as wood carving. In reality, most people can teach themselves to program, you don’t really need to take courses, except for guidance in some of the subtle aspects, e.g. how to write *good* programs.

Algorithm design is another thing altogether. Few places teach problem solving or algorithm design, because they are things that involve aspects of design, and a lot of thinking outside the box. Likely if we did teach them, they would be much too theoretical, and full of the “constructs of academia”. Science on a whole does not do problem solving very well, because they take on the problem solving mantra in an all-too-logical Spock-like manner. That and problem solving is something that comes with experience – the more life experiences you have had, and more things you have seen, the better you are able to put problems into perspective. But problem solving does not need to focus solely on computing, students could learn a lot about problem solving from the natural world, or dealing with real-world physical problems. Take for example the task of creating a user interface for a card-based payment system on a transit system. To properly understand how it should function, a good designer would be a transit rider, have travelled on the transit system in question, and have knowledge of how similar systems in the world operate. It could very well be that a solution already exists, and the wheel need not be reinvented. Similarly one cannot assume that an existing system will be perfect. A person who designs such a system at arms-length, never having been a commuter, will never understand the intricacies of its design. It’s no different with engineers who design subway cars without ever having travelled on a subway.

Many computer science programs fail to properly instil proper problem solving skills in students. Without these skills, algorithm design becomes quite challenging. But in the broader sense, we are slowly failing our students. Why? Because the world is becoming increasingly complex, and students need problem solving skills more than they need things like AI. You can’t design algorithms if you don’t have a basic understanding of problem solving strategies, both within CS, and the wider world.

Assume nothing

For the current assignment in legacy, I re-engineered the Fortran program as well… basically I nearly always check to see that things work okay. I did the re-engineering of the Fortran program, which calculates the volume of logs in board feet. No problems there. Then I added the functionality of calculating the volume in cubic metres. Easy I thought, and I added the functionality, and ran some data through it. It seemed okay, until a student wondered if their calculations were okay, being a bit off. Their answer was 2.04, mine was 1.91… not horrible, but then again not exactly a small error (probably would have lead to some wastage at the mill!). So what was wrong?

I did the calculation on paper, which involved converting both feet and inches to metres. Was I using the wrong conversion factors? No. Was I performing the calculation incorrectly? No. So I printed out the intermediary values. The culprit? The variable I was using to hold the value of the metric version of “tree length”, was named “mtl“, which I had forgotten to declare. But Fortran took care of that, because I did not use the phrase “implicit none” inside the subroutine. So the compiler implicitly assumed that because the variable began with an “M“, it would be an integer, meaning that the value calculated was rounded, giving the wrong answer. The solution? Declare the variable as a real. Problem solved.

The Lesson? When re-engineering a program, assume nothing, test-test-test, and check values produced manually. It happens to all of us I guess.

Mediocrity in programming

Computer science is founded on the principle of writing programs. In the modern realm it is sometimes overshadowed by more “fun” topics like app development, or AI. But fundamentally none of these things matter if programs aren’t designed and written properly, and this means they operate in an effective, and accurate manner. It also means that the software is usable. Of course designing a half decent piece of software requires an understanding of programming languages. The problem is that the world is full of mediocre software, written by people who don’t really have an understanding of software, or writing real programs. Learning to program in only one language like Java or Python does not make you an all-encompassing programmer, just like knowing C, C++, and Java doesn’t give you much programming diversity  (they are all C derivatives).

Mediocrity in software design is also a manifestation of an inability to think beyond the digital world. Developers should not forsake the real world in order to develop software – this is seen quite often in the lack of proper user interfaces. Sometimes this is because people just don’t think. Here is a case in point, and one I have alluded to previously – the TTC’s Presto system. While many other transit systems provide good feedback on the use of Presto, the TTC provides none – it’s excuse? Privacy. While privacy may be important, does it trump usability? No, and here is why. When I use Mississauga Transit it tells me how much is left on my card, and when I transfer from one bus to another, how much of my 2 hour transfer I have left. This is incredibly useful information for the user, and the time it is displayed is just enough for me to see it, people around me don’t see it, or don’t care. With the TTC, I am forced to actually log on to Presto to find the remaining balance on my card, which honestly is a pain. 2-hour transfer? Remember the exact time you got on the first vehicle.

If you are in computing, you should become a good programmer, even if you move into a field like HCI – you have to have a fundamental understanding of programming. If you don’t like programming, then maybe you should reconsider your career choice.

 

The [over] complexity of experiential learning

Experiential learning is no panacea. There is a lot of academic literature on experiential learning, but it almost seems like there are few real applications. I think this is largely due to the constraints of the classroom. But it also has to do with academia taking a quite simple concept, and twisting it around in the typical academic fashion. So experiential learning doesn’t just involve  hands-on “doing” of activities, but also includes reflection and abstract conceptualization before applying learning to a new activity. What a load of tripe. Reflective learning experiences – I don’t know why we persist in making a natural process seem so complicated. Yes, some of what we do is reflective – when I make a pastry, I am always looking at how I can make it better, or learn from mistakes. In fact it might be the learning from mistakes which actually makes the experiential learning worthwhile. Maybe we should call it “failure based learning”? Some of what we learn occurs through pure absorption of the world around us. You can learn a lot about ecology just by walking through a forest, and observing life there. You don’t need a textbook. In fact even better is to grab a camera, and photograph life in the forest… then discuss it latter in group discussions.

But back to the baking example. Baking involves somewhat of a trial-and-error process. Although it is often touted as being a very scientific process, unless the ingredients used and baking environment are replicated exactly, it will be hard to have 100% success. So the experiential learning aspect of baking has a very iterative effect. A simple recipe for scones may not work, either because the flour is different, or they lack moisture, or the oven temperature is not optimal as it relates to the recipe. There is never a guarantee of the same baking outcome as shown in a book. Baking is exceptional for experiential learning because it does require some level of reflection at the end of a bake – what could possibly be done to make the next bake better. This is done in a very organic manner, much like one would reflect on the process of doing anything.

Experiential learning is but one way of learning. It is something that exists in a shop class or art class without any thought. It has existed for thousands of years, and was likely the most prominent way of learning skills. What we don’t need to do it over complicate it by adding fancy terminology, and writing thousands of pieces of inconsequential literature. Just find a way of incorporating it into our classes, and explore the world around us.