An APR & Rebate Calculator for the OFT
The DualCalc Blog ...
(Page last updated: Monday 7th August 2006)
I have agreed to develop a Windows rebate calculator for OFT which will carry out the calculations required by the new 2004 Regulations, so I thought I might record my progress and thoughts here in a web log or 'blog'.
As is the way with these things, the entries are presented with the older ones at the bottom, so you can read the more recent ones first. Backwards text the type actually won't I strain brain undue avoid to, however.
As is also the way with these things, I didn't think to do it until I had already begun the programming, so the first (ie last on the page) few entries are a bit vague as to timing etc.
PS: the log has also subsequently been used to record on-going changes after the initial development and provide an achive of the history of older versions of the program - see the menu on the right - for more recent version information see the help files packaged with the program or the CRW.
Note: this log contains my personal reflections on the events described, they should not be regarded as the views of any other person or organisation.
Monday 7th August 2006 - Log Re-opened
In view of the continuing development of the program, and the growing version history, I have decided to re-open this page and transfer information on older, pre-release, versions (prior to v1.01) here.
Other material may be added over time to keep the version history in the program's help files to a reasonable size.
Friday 11th February - Log Closed
The Office has now obtained its own copy of BBC BASIC and the source code has been passed to them for compilation. Any further changes will be recorded in the version/history log in the program's help files, this log is now closed.
Although this blog is, technically, finished now, I will continue to use if for the time being to record any subsequent amendments to the program etc ...
Monday 7th February - one more thing, while I was testing the program Friday I realised it was a bit annoying to have to keep 'manually' adding 28 days to the settlement date I wanted to use, so this morning before leaving I included a small tool to do this by adding a '+28 days' selection to the deferment selector, which adds 28 days to a date in the settlement box when you choose it. It uses the same dialogue change detection method as the settlement selector but it's really, in effect, just providing a 'button' in the selector.
While showing the program to someone last week I noticed that they assumed it would understand 2-digit years in dates. Consequently I've added a function to recognise 2-digit years and convert them to the nearest (within 50 years) 4-digit date.
I have also started to think about some of the 'hooks' needed to extend the program a little - eg to run other utilities which interface with DualCalc. To this end I've split parts of the load and save calculation routines out from the sections which ask for a filename. This is so the program can automatically save the current calculation before loading a utility (eg because the utility is a CHAINed BBC BASIC program which will need to re-load DualCalc and it's calculation when it's finished, or because the utility will manipulate the current calculation in some way).
I realised there was a problem with CHAINing other .bbc programs because only the compiled version of DualCalc is available to CHAIN back in after. To resolve this the program now saves it's (crunched) .bbc code in the resources folder when it starts.
Leading on from this I've also added a facility to autoload a calculation at startup with a -load:
This new load routine also gave me an opportunity to enhance the loading of saved calculations so they can automatically run and log calculations and then chain another saved calculation - so you can batch process a whole sequence of them.
Sunday 6th February - Fixed three other minor but important things:
Saturday 5th February - I was determined to have a weekend away from this but we couldn't get to the bottom of the anomaly mentioned below yesterday, and instead found another - when you added a deferment to an actuarial calculation the rebate when UP instead of DOWN ... looks like a program error but I can't find it ... so I need to resolve this.
I built the actuarial routines by taking the Rule of 78 ones and adapting them - with bits of the APR routines added in for good measure. I thought this might eventually come back to bite me, but I didn't recognise it when it did, until just now. The problem with the deferment was that the Rule of 78 calculation doesn't need to add up the payments on or after settlement, so where they're needed for the actuarial calculation, I calculated them as the TAP less the payments on or before and then added the payments 'on'. But the R78's 'on or before' payments were based on the settlement date, not the deferred settlement date needed for the actuarial calculation. Consequently, while the deferment was adjusting the payments before settlement included in the formula's calculation, it was still using an un-deferred value for the payments on/after. This took ages to track down but has now been corrected by adding lines of code and variables specifically for totting up the 'on/after' values.
On the plus side, I also found and corrected another rather careless error in the Rule of 78 routines - at one point the time of the last payment was checked against the deferred settlement date rather than the actual one.
Still haven't looked at whether this resolves the rebate>TCC problem, but it might have.
Friday, 4th February - one minor change, the actuarial analysis was now correctly calculating the 'before' values for extra payments with -ve values and adding them to the total (it had previously calculated them as +ve and subtracted). But I hadn't realised that it was also printing them as the -ve values, so now it was calculating them -ve and printing them +ve! Fixed it.
Thursday, 3rd February - Only had one bit of documentation to do, describing the logged output, but noticed that there was something wrong when I logged a pro-rata calculation. Tracked this down to a simple error in the complex pro-rata routine (the simple one was okay) and corrected it. There was a similar (but different) error in the pro-rata logging analysis, also corrected. When I got to the final log in the documentation (Actuarial) I noticed a weird anomaly - the rebate was more than the TCC. Trying to understand this led me to check through the whole actuarial analysis bit again. I found a number of careless errors (wrong variables, +'s where there should be -'s etc) which I corrected, but none of these explained the anomaly. Next I tried improving the analysis routines by adding some period/days reporting and generally re-doing lots of it, this took a fair bit of time but didn't make the anomaly go away (wasn't really expecting it to).
I haven't thought this through fully yet but I have an instinct that the problem might actually be the OFT interpretation of 'after' as 'on or after'. The 'right' way to do the calculation would be to include the 'on or before' payments in the formula and the 'after' ones in the sum remaining to be paid, but there was no reading of that in the Regs and we've gone for the opposite. I think the effect of this is that one of the repayments is inappropriately included in the rebate and this can tip it over the TCC early on in the loan. It all pans out when you work out the settlement figure etc, but it's perhaps an indication that there's something fundamentally wrong with the Regs (which really need to say 'on or before' in the formula's definitions). On the other hand it could just be a cock up in the program.
Anyhow, finished the documentation using an example which shows the anomaly, but without drawing attention to it.
Tuesday, 1st February - noticed that the HTML output had a few extraneous £ signs and was missing the odd '=' sign. Corrected.
Monday, 31st January - discovered yesterday while working on the documentation that the new 'zero rate' approach led to the html writing routine falling over when a PV analysis is logged - the composite PV formula won't accept a zero rate. Simply added 'IF EAR<>0 ...' to the relevant line. Also noticed while fixing this that the Actuarial before/after analysis had no '£' signs on the amounts for regular payments or levels. Added these.
Updated the build and .zip file.
Saturday, 29th January - while working on documenting the entry of dates and cross-checking with the program I noticed an anomaly. Using dates and changing the PPA from Years and days to, eg, Months made absolutely no difference to the final EAR result. I managed to track this down to a missing line from the old DOS version of the period calculation routine which limited the Years and days calculation of periods to cases where PPA=1 (Years&days).
I also noticed that there was no warning that the user was using periods and dates together or that there were no advances, and this lead me to start overhauling the routines to check for consistent entries and report on inconsistencies - split these out into separate routines removing a lot of duplication from the calculations.
While checking this, I noticed that the dialogue was being corrupted while loading the test calculation - the dates being read in were appearing in place of 'Settlement date:'. I managed to track this down to the DD/MM/YYYY to datecode conversion routine which was still handling writing values back into the dialogue but, in this instance, was being used with no specified dialogue item - and just happened to be using the same local variable for item number as used for something else in the load routine, which was set to a value which corresponded to the item number for the 'Settlement date:' label. Corrected this.
One of the inconsistencies looked for in checking the details is a loan with TCC=0, and this in turn lead me to a fairly major overhaul of the routines dealing with zero rate loans - in particular also creating a routine to calculate the sums paid, due etc for a zero rate rebate calculation.
This ultimately lead me to re-write the routines for checking and reconciling the APR/PER entry for actuarial calculations again ... twice.
Enough changes to warrant a version number, were I not sticking at 1.0 until pre-release.
Wednesday, 26th January - decided that I should slightly alter the way the help routine works to future-proof it. Now, it checks for a local set of help files in the help folder, and only asks the user if they want to go on-line if it's not there.
Tuesday, 25th January - met with one of our lawyers who has kindly agreed to check over the program before it's pre-release. Immediately hit a problem when I couldn't install the program on his PC so he could check it. It seems that on WinXP PCs where the user has some rights restrictions, or a particular 'profile' the *CD command, when used to change to certain directories, causes an error. The simple solution was to remove the *CD command which was only there to select the 'Saved' directory for Win95/98 users. [TO DO] this would be resolved by incorporating code to select the saved directory as the first to browse, this may also need an option for the user to set the data directory.
Week commencing 17th January 05:
Monday - essentially I can now bring this log to an end because the program has reached a 'first draft' stage and is therefore developed. I have therefore moved this blog out of the program's help folder in to an (archival) folder of it's own. I have also skimmed through it and labelled a number of things [TO DO], so they can be found easily. These will be picked up in the fullness of time.
Hey look! I got all the way to the end without mentioning again how much better RISC OS is than Windows ... Doh! ;o)
I do however still have to write some useable documentation and this inevitably forms part of the development process because, while describing it in the text, you often realise that something doesn't quite make sense or could have been done better, or you check exactly how something works before describing it and hit a glitch. So these sorts of things get fixed in the process of writing the documentation. I've often wondered whether I should try actually writing the documentation first and then try to get the program to do what it says.
From now on I should probably keep a, less frequent I hope, Change Log on the site so that those testing the program can check for newer versions and see what's been changed. Until testing actually starts I'll leave the program at v1.0 (beta) and then broadly follow Richard Russell's method of numbering. Version 1.0 also neatly sidesteps my programs - DualCalc v0.1 to v0.4, which are now defunct, superseded by the OFT's program.
This morning I tidied up a few remaining technical issues like enabling the 'proper' error handling and recompiling the testbuild with a 'hidden' window so there is no start bar button and it sits neatly in the middle of the screen.
Discovered that Richard was right about selecting folders after all - but only in XP it seems. Interestingly XP also seems to ignore the selected folder so my 'Saved' fix kind of works both ways, in XP the user starts back at the folder they last used (although they have to go find Saved the first time) and in 95/98 they always start in the Saved folder (although less convenient if they want to use another one). [TO DO] Ultimately this needs to be fixed by using the API call to open in a folder the user can specify in Options.
Week commencing 10th January 05:
Sunday - want to get this finished and get on with the documentation but there's something nagging.
The flag saving fix I did yesterday works but there's another flag and value used too, to store Days in year internally. When the flag's set the value is 365.25 but the program uses 365&366 days, when it's clear it uses the value. I didn't want to use another saved variable to store this flag - and anyway I couldn't think of a good name for it - so I decided on a different approach, saving 'DIY=365&366' when the flag is set and the value otherwise. Realised this was also a better approach to the deferment issue so changed this to saving eg 'Defer=Stat_1' for a statutory 1 month deferment (or _2 or _30) and leaving the 'Stat_' off where it's just a value. Had to edit all my saved examples but I'm happier with that.
Also took the opportunity to fix something which had been annoying me - I had had to include 'Zero' among the combo-box deferment options for testing to stop it getting detected as 'INVALID ->'. Managed to get rid of this and the user can now enter '0' or Zero and have it accepted.
I think that's pretty much it for the programming - of course I will be proved wrong.
Decided to take a look at the image map idea for the 'interactive' help. I have some RISC OS software to do that, to I grabbed a copy of the dialogue using the -display switch (did I mention I added a facility so none of the boxes are greyed if you put '-display' in the command line?) and saved it as a .png., Converted it to a Sprite in RISC OS and after a bit of a false start, mapped out all the areas - fifty-bloody seven of them, my eyes, my eyes! Save the client-side code in HTML and tested it in Oregano2 (A RISC OS browser) all seems okay. The various rectangles in the map are labelled area1 to area57 and these will appear if you hover over them in IE and some other browsers - I'm sort of hoping a load of ufologists are going to end up here after googling 'Area 51' - but I doubt it.
Finished up by shuffling around the files and folders a bit to prepare for adding proper help files. Got a bit side-tracked. My ISP's server is easier to use if the names are all in lower case and they weren't. After renaming about twenty by hand I gave up and wrote a little RISC OS program to go through all the folders and sub folders renaming everything to lower case.
Put it all up on the site.
Saturday - yes, I know, Saturday morning. Did a little more testing and discovered some glitches in the HTML building routine - I think I got all these ironed out but it's time to go see Man Utd thrash Liverpool.
... time passes ...
Okay only 1-0, and 10 men in the end, but it's three more points.
While doing further testing on the HTML generator I noticed that the load routine wasn't picking up the deferment correctly. Realised I hadn't done anything to save whether the deferment value was statutory or not (internally the program uses a flag and a value to store the deferment, if the flag's set only values of 1, 2 or 30 are used and they mean the statutory deferments of 1 month, 2 months or 30 days, if the flag's clear, the value is counted in periods - the way I had it 30 days would have been loaded as 30 months!). Fixed this by saving the flag as well with the name 'StatDef=' and modifying the load routine too - all seems okay.
Friday - working at home. Put simply, added an actuarial rule analysis. In a little more detail this also involved:
- adding to the calculation save routine so it remembered the setting for outputting analysis details
- re-doing the conversion of APRs to period rates in the actuarial calculation to ensure that the truncated or rounded rate is used.
- a general run through of some of the code and miscellaneous minor additions/amendments
I am concerned that the time I was expecting to spend adding the printing routines was instead spent adding the analysis code to the logging routine. I feel I'm running out of time and still need to make a start on the documentation so, as there is a 'quick fix' available I've decided I will use the user's browser for printing as an interim measure. I've split out the code to output the results of a calculation in HTML into a separate routine and added a printing routine which is very similar to the logging routine apart from always starting a new web page and using a version of the standard template which includes 'onLoad=print()' in the pages body tag. It also automatically opens the page once it's built.
So, when the user clicks 'Print', a new web page containing the result is built and then opened and the print() command starts it printing. That sounds good, but what happens next is the print dialogue is thrown up and the user has to click on the Print button in that ... and then close the browser window afterwards, so it's a bit irksome really. However, this is only a temporary measure [TO DO] proper printing routines are still on the agenda.
Sadly on testing I discovered that, on Windows 98 at least, the compiled program does not seem to operate as Richard Russell suggested, remembering where it did save/loads last time. It always starts in My Documents. However, I noticed that simply choosing another folder in the program code beforehand overrides this, so it is possible to make the program start in the 'Saved' folder. Ultimately the user should be able to select their preferred folder, in an extended 'options' dialogue.
Thursday - updated this log at home before leaving. Felt a bit yuck when I got to work but started on the analysis of R78 calculations. Finished these but felt worse and thought I'd better go home again. However, I obviously wasn't concentrating and as I was about to leave, discovered I'd mucked up a big chunk of the logging routine. Didn't want to leave it in case I lost track of how to fix it, so I had to do that first.
Felt a bit better when I got home and managed to finish the R78 analysis and add Pro-rata analysis (very simple) in the evening.
Wednesday - checked my mail this morning and had a reply from Richard Russell. Extremely helpful (as usual) both in explaining how to open a particular folder in more detail and in how to determine the page (printable area) width.
Armed with this I could start on the printing routines but, on the way into work, it occurred to me that the logging routines hadn't implemented the 'analysis' option - this provides the user with more information about the calculation in an effort to deal with the possibility that, eg, a court might ask a TSO to 'prove' that the APR result is correct. It does this by adding to the output details of PVs and their totals for APR calculations, the top and bottom halves of R78 fractions etc.
I mused for a bit about not bothering with the analysis routines (these were a refinement of the more advanced versions of the DOS programs) but then realised that they were very important in the testing stage because they provided a way to double-check how the program had done the calculation - they really do need to be there (they're probably also going to be useful to the Office internally for producing guidance material, because they'll spit out all the figures for examples).
First thing when I got in was I discovered that the options dialogue wasn't retaining the current setting for the 'Analysis' tick box, so I fixed that and also thought to add 'Details=' to the switches which could be set by Setup.txt.
Then I ummed and arred a bit about whether to do the print routines first and then add analysis details to printing and logging, or spend more time on logging to implement the analysis stuff there. Reasoned that if I had the analysis stuff in logging it would provide a model for printing too so I should probably concentrate on that.
Slow going - but, by the end of the day, I had built the logical structure for analysis and added PV details to complex APR output. The logging routine is getting very long, maybe I should break it up a bit.
While testing what I was doing I discovered that it is a pain to keep the logs and saved calculations in different folders. Since they are different file types (htm and txt) only the relevant ones appear for the relevant load/save actions and, so I moved them all into one 'Saved' folder.
NB: Forgot to mail the source code home so it's still yesterday's version here and the load/save/log routines may be broken because I typed complete nonsense instead of the correct code to check whether the user had added an extension to a file name.
Tuesday - quickly implemented a couple of configuration facilities before leaving for work this morning: the file 'Setup.txt' in Resources can set the switches to determine the type of calculation displayed on startup and the file 'Maxima.txt' can be used to determine the maximum numbers of advances, levels and extras the program will deal with. Both are in 'saved calculation' format and Maxima.txt uses the 'Advances=', 'Levels=' and 'Extras=' indicators for the maxima. Due to a rare piece of forethought the VCR handling and dialogue building routine (which uses different buttons and actions based on the maxima) had already been coded to cope with different values - as had the code to ensure that the maxima were rounded to the nearest ten so as not to confuse things given that there are ten entries in the panels. There is a trigger value for the different actions - maybe that should be configurable too?
I was concerned about how I could make the program open a particular folder when you browse and emailed Richard Russell. He tells me that Windows automatically opens the last window visited, so that shouldn't be a problem with the final compiled program - I was not getting this effect because I was running the .bbc code from the editor. He has mentioned how to access a particular folder but I didn't really get it and it's not that important.
At work I had some proper job stuff to do and then turned to the printing routines. I started by adding the code to call the Windows page setup dialogue from Richard 'Hints and Tips' page on his site and a button in the Options dialogue to pull it up.
Then I started to look at printing, the only problem I can see is that, with proportional fonts, you have to adjust the place they're positioned on the paper to do things like centring. Richard provides code to measure the length of a proportional string and shows how to, eg centre it on a given positions across the paper. But I can't see how you work out the width of the printable area so you can centre stuff on the page or, say, right justify it. So, I've prevailed upon him again to see if he can tell me how to do this.
In the meantime I think the best thing to do is copy over and adapt the logging routine, but not worry about justification yet.
Monday - due to an hilarious (actually just plain stupid) 'wrong trousers' incident, I arrived at the station this morning with no season ticket, credit card or money (even more amusingly, I had just enough change to get there on the bus - but only half-way back), so I'm back here at about 9:45am working at home again. Please bear in mind that a bloke who can't even dress himself properly is writing this program :-O~ (drooling).
Spent all day ploughing on through the logging routine until I got it finished - slightly gob-smacked at how much thought and code was involved in the end and I also had to alter a few other things (like separate the 'number formatting' code from the 'writing it into the dialogue' routine) to integrate logging better. Ran it with some basic examples until it would go through to the end without error and amended a few glitches in the format. It's not been otherwise tested but I've put a build up with this blog entry.
NOTE TO SELF: there are a few things mentioned here (like HP half and third info) I haven't done anything about yet - I need to read back through this.
Oh ... oh ... and the files open/save routines need to add extensions when the user doesn't.
It's about half six now so I've had enough for today - and anyway I need to spend some time on trouser recognition exercises.
Week commencing 3rd January 05:
Friday - working from home today, started about 7:30am and by 9 I'd finally got the APR/PER reader right. Realised that the simple versions of the file open/save dialogues I was using (in BBC BASIC for Windows, if you open a file with a wildcard name, it automatically calls up the dialogue) weren't really good enough, so I substituted routines which call the Windows API.
While testing this I noticed there was something wrong with the complex R78 routine - it was giving the total paid as zero for level only loans. Found I'd moved, instead of copied, some of the code to the complex Actuarial routine, so I put that back and it's okay now.
I'm still not sure about the complex Actuarial routine though - regard it's results as suspicious!
After lunch I added some code to the program initialisation so that a '-display' switch in the command line will cause the program to initially switch everything in the dialogue on. This is purely to generate a dialogue that can be used for the help files. The result looks like this:
Wrote a routine to select and display a log file (really, any HTML file) so I could examine the results of the logging routine when I wrote it.
Began work on the logging routine. It will use a template file which the web-skilled user can amend but started by getting the program to write a simple default one if none is present. Wrote the basic file handling structure for the routine and dumped the code from the save routine in there in 'pre' tags, just so there would be some output. The way I've decided to work it is as follows:
Began to test this but there are some strong winds today and they seem to be getting the better of our power supply. The lights keep flickering so I'll give it best now before I lose something, it's 4:30 anyway.
Thursday - completed the load routine, tested it and corrected a few glitches. Save/load all seems okay now, apart from the APR/PER in actuarial calculations. Decided I wasn't happy with the section of code which read the APR and PER from the dialogue and basically re-wrote the whole thing, but it's still not quite right.
Added some code to the initialisation so that the program makes its resources folder if there's not already one there.
Wednesday - had some 'regular job' stuff to do in the morning and a meeting in the afternoon and then continued with the load routine. Not much progress today.
Tuesday - began with a mail to the credit teams about the questions mentioned below. Continued work on the loading routine. I have chosen a slightly slow approach where the routine scans the entire file for the first occurrence of each of the variables which make up a calculation. This way users or programs which construct calculation files won't have to be particularly careful about the order in which stuff is put in the file.
I added my standard recursive file search routine to the GENLIB code and wrote a small function FNscanFor("text") which uses it to look for "text", starting at the beginning of the file, and then return the text from "text" up to the next terminator. A 'terminator' is comma, semi-colon, space, tab (ASCII 9) or CRLF (ASCII 10 or 13), to allow programs to generate calculations in a number of formats. So, if the file contains 'Loan=1000' followed by a terminator (by default a CRLF - this is how DualCalc saves it) then FNscanFor("Loan=") (incidentally, it's case insensitive) will return "1000".
Finished splitting out the date checking routine and this seems okay.
Monday - decided to take a look through the code to 'tune back in' after a week away before I start back tomorrow ... and ended up writing some. I completed a calculation saving routine and began the corresponding loading routine.
I will need some way of checking whether time values in saved calculations are dates - I'm in the process of moving the checking routine in FNreadDate (the function which reads dates from the dialogue) to a separate validation routine.
The format I've chosen is a simple series of text lines (ending CRLF) which have the format variable=value (eg, Loan=100, Initial=0, etc). I abandoned the XML format idea, easy to save but harder to parse in the way I wanted to when loading. It should be possible for users to construct saved calculations themselves (eg with other software/programs - not much point in doing it manually!) to generate calculations the program can load. I will eventually add 'variables' which will tell the program to do the calculation, log or print the results, and load another saved calculation - this way it will be possible to batch process a number of previously generated calculations.
As part of the saving process, I had to move the reading/checking of the APR/period rate entry for Actuarial calculations into FNcheckData and have REMed out the part of the Actuarial calculation which calculates the APR first. I have also decided not to implement simple Actuarial calculations at this stage, because they provide no date entry facilities and, the way the Regs have been written, virtually all calculations will require date calculations (because of the 28-day deferment and Reg 11 TCCRs). Need to talk to the credit teams about this decision, and about whether the current method of calculation will need to be retained (eg so users can do 'pre any later change to the Regs' calculations.
I also altered the way that the program displays it's copyright message, it now does this every time it processes a user action, that way the individual actions which change the info line at the bottom of the dialogue don't have to bother, and they have been altered correspondingly.
NB: the build has not been updated yet, because I've not checked these changes are all stable.
Week commencing 27th December:
Monday - Friday - on leave.
Week commencing 20th December:
Friday - on leave.
Thursday - on leave.
Wednesday - tidied up the settlement code in the morning and worked out and REMed in how to add lastPay into the rebate calculation if needed. On the train in I decided I'd try to find out exactly what the formula in the Regs was doing and, although I only had a simple 'Planner' type program in my Psion, it seems pretty clear that what it's doing is calculating the balance due - including the instalment due on the settlement date. I thought that was a bit odd at first but I'm guessing that GAD gave DTI a formula to calculate the sum due on settlement (ie everything due, including the repayment) and DTI then had to convert that into a rebate calculation because s95 of the Act only allows for a rebate formula.
The meeting with the lawyer and a the credit colleague was very useful and I now understand that there is an argument that the wording in the head to Reg 4(1) can be read sensibly to include the payment due on the settlement date because of the conditional clause about 'if settlement did not take place' - ie the initial premise is that the borrower is going to settle, so the instalment due on that date is catered for by being left out of the rebate formula and hence remains outstanding. However, if they changed their mind and didn't settle on that date, then the instalment would immediately thereafter become payable and so should be included in the sums from which the result of the formula is deducted - and this is re-enforced by regulation 3(1) which requires that 'the rebate shall be calculated by reference to all sums paid or payable ...' (my underline) so you can't just leave one of the payments out entirely. Okay, I feel that's a bit of a stretch, and we agreed Reg 4(1) really should say 'on or after', but I can accept that if it's the Office's view.
Of course what this does not explain is why the example completely contradicts this by saying that the balance 'after' payment of the 12th instalment is calculated 'according to the formula' and including the 12th payment in the formula so that it does. I understand from the credit team there are some other problems with this example too, but the Regulation takes precedence (Reg 4(3)).
Changed the program to incorporate the lastPay adjustment. I also realised that the user might want to enter a period rate rather than APR so both these now open with the APR being used for preference and the period rate only if the APR's not entered/valid.
I'm on leave until January 4th so that's probably it for now.
Tuesday - there seem to be quite a lot of issues in the examples and I spent a good bit of the day wearing a groove in the floor between my desk and the credit section:
There were some emails between myself, the credit team and our lawyer specialising on this subject, on the 'before' and 'after' point and we've agreed to meet to discuss it tomorrow morning.
In the meantime, I looked through the code of the settlement calculations for a fix to include the 'on' payment in the calculation and came up with a pretty simple one - the program also calculates the sum payable on the settlement date so it can report the total payable, settlement figure plus final payment and, if this figure should be included, all I need to do is add it into the rebate calculation.
This also gave me a chance to look through the settlement calculations again and pick out some things which need tidying.
Monday - spoke with the credit team about some of the further points I'd concerns about. As the main problem was the way I'd interpreted 'before' and 'after' and the conflict with the first part of the first example in the regulations, he felt it was better to check my interpretation with our lawyers before approaching DTI.
He also mentioned that DTI now accept that the agreement's original APR must be used for the actuarial calculation and will amend their Guidance - so there is no alternate 'DTI Guide' calculation. As an interim measure I have blocked out the method (now called 'Revision') which calculates the APR first ... although that maybe should be available in the test phase.
Decided to get on with my proper job because I couldn't really do any more until this was resolved.
Week commencing 13th December:
NOTE: the current test build seems to give the wrong answer for actuarial rebates - ie it doesn't agree with the Regs.
Friday - spent most of the time looking through the Regs and scribbling diagrams until I eventually wrote some calculation code for the complex actuarial routine but they don't work correctly yet as far as I can tell. I have however realised that I can use the FNlevelPV() and FNextraPV() functions to do the calculations, the level one needed a bit of thought as the times are all counted up to the settlement date rather than on from the relevant date, but in the end I just used them 'backwards'.
Bit of a frustrating day generally, every time I look at something in the new Regulations it just raises more questions:
My brain, my brain!
To cheer myself up I implemented the mechanisms to do both complex Actuarial and 'DTI Guide' calculations in the one routine. PROCgreyMode() has been modified for the umpteenth time so that it opens the APR box when the user chooses an actuarial calculation, and the calculation routine also pulls the value out of there for actuarial calculation or calculates the APR and puts the rate in there first for a DTI guide calculation.
I've just noticed while writing this that the first example in the Regs has no deferment, so things might not be as bad as I thought.
Oh, and I made the icon a bit more colourful.
Thursday - on a half day but began working in earnest on the Complex Actuarial calculation. Wanted to ask the credit review team whether the calculator should allow thirty-day deferment when the user was not using dates but they were out, so I made a unilateral decision that it would reject such calculations and ask for date entry. Built the basic structure of the routine from the complex R78 version but it doesn't do anything useful yet so I'm going to put a test build up.
Visiting the R78 routines again prompted me to do a bit of simplification. I've written a function FNlevel78() - all of about 30 bytes - to sum an R78 level and used this in both the complex and simple calculations. Also noticed I'd forgotten to deal with the Final payment in the complex calculation (oops) so corrected that. Also re-wrote the calculation in the simple R78 routine so that they used the settlement and deferred settlement dates - rather than the settlement date and the length of the deferment - this makes the simple and complex versions consistent.
The credit team told me that DTI confirmed my assumptions about the calculation of r - so that's okay.
Wednesday - finished off my general tidy up in the morning and had a Christmas drink in our section lunch time. Went back to the Actuarial calculation in the afternoon and didn't understand DTI's description of converting APR to r in the formula, so I looked at the Regs and didn't understand that either - thought it was the drink at first so went back to my colleague dealing with the Regs and he saw the point that the Regs are ambiguous. They say something like r is 'the period rate equivalent of APR/100', but does that mean '(the period rate equivalent of APR)/100' - I think that's what it should be, ie the period rate expressed as a decimal' or 'the period rate equivalent of (APR/100)' which seems just nonsense. I don't think there's a problem in terms of the program here, but what if a lender starts giving, or consumers start demanding, rebates based on the second method? Need confirmation from DTI that the first version is their view though.
In the meantime, I decided to enhance the series entry so it would do advances too. This kept putting stuff in the wrong arrays (extras instead of advances) etc. until I finally discovered that several of the combo box routines (called to check the data before the series is added) were using the same variable which determines extras/advances without it being declared as LOCAL - so they were changing it and then the series routine was putting stuff in the wrong place.
At COP the credit team came back to me for a brief example of how the two interpretations caused different results which he's going to mail off to DTI.
Tuesday - had a brief informal meeting with a couple of the credit team to show them progress so far, ask for any comments and check on a couple of questions: whether advances should be disabled when R78/PR rebates are used and whether the program should display HP half/third info in price calculations. The answers were seems okay, 'yes' and 'yes', although it was rightly pointed out to me that you probably wouldn't fire up this calculator just to calculate the HP figures.
Began to look at the Actuarial calculation and hit a problem with DTI's guidance. They seem to be saying that payments falling within the deferment period are payable by the borrower and I think that's wrong. As in the old Regs, the new ones say that the deferment is 'for the purpose of calculating the rebate' or something similar, not for calculating the sum due - ie the deferment reduces the rebate a bit but doesn't mean the borrower has to actually pay payments due after they settle. Checked with a colleague in the credit review team and he's going to talk to DTI. As this would affect the way the DTI Guide calculation was coded (and might mean separate routines for that and the Actuarial method) I'll have to wait for an answer.
Fiddled around with some general tidying up. The combo box routines were all using different variables for the same tasks so I made them uniform and shortened the way they handle 'INVALID->' reporting. While working on series entry I noticed that the date reading routines didn't write dates back into the text boxes so I added this and also removed the evaluation of non-date entries as this seemed a bit ill-thought-out: how should the program distinguish between a date and a calculation which has two decimal points or two subtractions or divisions in it? This might need a bit of a re-think.
Also discovered a few more things where I needed to 'generalise' the dialogue handling.
At some point the credit team came back to me with the information that DTI didn't mean to say what they'd said, so I should treat it as a deferment in the normal sense, but it's near COP ('close of play' - civil service speak for the end of the day) now so I'll turn to that tomorrow.
Monday - Looked up the formulae for the simple R78 calculation, copied and cannibalised the complex code before adding the simpler formula. Worked first shot, so that's crossed off.
Decided I needed a bit of restructuring of the four routine plan below and made it a little more hierarchical. Now the calculation routines are structured in three groups - APR, Rule of 78/Pro-rata and Actuarial/DTI Guide, each of which has simple and complex versions. There is an initial PROCcalculate which branches to PROCcalcAPR or PROCcalcRebate. PROCcalcAPR does the data checking and, in the case of complex calculations calls PROCtidy and PROCtotalPays before going on to PROCsimpleAPR or PROCcomplexAPR. PROCcalcRebate is an additional layer in the hierarchy which branches to PROCcalcRule78 or PROCcalcActuar and these then act like PROCcalcAPR by checking data etc before branching to simple or complex versions.
Hooked all that together and it's working well.
Thought some more about controlling the setup for printing. I didn't think the simple switch from Standard to Detailed output was really enough, the user needs to be able to pick a printer and probably a font too. Changed the button to a 'Format' button which opens another dialogue containing print and font setup buttons (which in turn pull up the standard Windows dialogues) and a tick box for including the extra details, this all pretty much worked first shot, but doesn't do anything yet because there are no printing routines:
(Just realised that I've used the RISC OS vernacular 'Dismiss' - this should probably be 'Close' ... and why is the prompt for the tick so long? 'Include analysis:' would do.)
Having produced one additional dialogue, I got slightly sidetracked into series entry. Wrote an additional dialogue builder for a small dialogue with which the user can enter the amount, start time, interval and number of payments, a combo to select intervals as periods or months, and an 'Add extras' button to start inserting the payments in extras. This still needs to have some code written for the combo and the actual insertion code.
Started work on the series entry stuff but kept coming up against the problem that all my library routines for dialogue handling were designed to work only on the main one. Now I had three dialogues I was having to treat the series one (the format one was much easier) as a special case and write specific API calls for it every time. The fix was simple, all I had to do was include the dialogue handle as one of the parameters passed to the library routines, but it meant that, as soon as I'd altered them, the entire program was broken until I'd found and modified all the calls used for the main dialogue. This took quite a time.
When I'd got that fixed and was testing it, I noticed that the simple and complex rebate calculations were giving different results for the same loan when Extras were used. Thought I was in for a lot of back tracking, but I decided to start by throwing back the values for the amount and time used in the extras routine and immediately discovered that they were zero. It turned out I'd typed N% instead of n% when reading the amount from the array. As N% is one of BBC BASIC's 'static integer variables' which always exist, I wasn't getting a 'No such variable' error but as I don't use N% it was zero, so it was reading element zero of the array, which also isn't used and contains zero, hence all the extras were treated as £zero - grrr.
I'd written a few lines in the complex rebate calculation to add x months to a date (for adding deferment) and realised this would be better as a general routine so I could use it to add months to a series as well. Transferred it over but completely cocked it up and didn't notice until later.
Discovered that the use of multiple dialogues needed a bit more thought - eg what to do if the user clicks on the close icon for the main dialogue while one of the others are open. This needed a bit of a re-write to the basic wimp poll routine (sorry, RISC OS terminology - the bit where it sits and waits for the user to click something), at some point this caused another BSOD ('waiting for the close program dialogue to appear') but Windows acted a little more intelligently this time (ie it actually knew it has crashed on a restart) and it's been stable since. The dialogues all seem okay now.
Went back to the series stuff and realised that it needed it's own wimp poll and it's own checkData() equivalent. Implemented these and started on the filling in the extras bit. Came to a bit of a stop because I couldn't make up my mind what to do with certain input circumstances: if the user enters a start and relevant date and chooses intervals in months, fine, all the extra entries are dates x months apart; if they enter a start time and choose intervals in periods, fine, the extra entries are times calculated as start+n*interval; if the user enters a start time and intervals in months, uh, uh, they have to give a start and relevant date for month entries; but what if they enter a start date and intervals in periods. Well they still have to have given a relevant date or the start date is useless, so that's a no, no too. What I settled for in the end is, if they've given a start and relevant date but choose intervals in periods it calculates the start date as an integer (rounded) time and then all the time entries are calculated as start+n*interval. I think that's what the user would expect. Series entry is crossed off the list.
Week commencing 6th December:
Friday - The credit team arranged a meeting for this afternoon with me, representatives of the credit team and IT at which it was agreed that I would continue development as before. Sadly this has cost us a week.
I added the dialogue stuff to the complex Rule of 78 routine and modified greyMode() - again - so it would deal with enabling just the TAD, TAP and TCC results for rebates, and also grey the Advances entries for complex R78 calculations (not sure this is strictly necessary but, since the statutory R78 calculation doesn't allow for multiple advances it seemed appropriate). Bodged the R78 results section slightly so they will clear the rate results - this should probably be in greyMode() but it makes more sense here. [TO DO] Thought about using the spare rate entry boxes to display the 1/2 and 1/3rd HP figures for price calculations as this info was provided by the DOS programs - I'll ask the credit people if it's useful.
Greying the advances was quite interesting, to do this I had to detect changes to the combo box in real time, not just when the user clicked a button. I thought you couldn't do that and have compromised on this in other programs, but I though I'd have a go a doing the detection inside the system call loop of the poll routine and it worked! Ah well at least I've learned something useful. There is a bit of 'flickerage' if the user types something in the combo (it repeatedly labels it 'INVALID->' until they select from the combo again, this probably won't be visible on a faster PC and I can live with it.
Haven't done much testing of the Complex R78 calculation yet but it all looks pretty much okay. It uses the same trick as the old programs, do the R78 calculations and then replace the resulting fraction value with a simpler Pro-rata fraction, so it handles these calculations too. Crossed them off the list below.
NB: currently, the test build is still the one from last week.
Thursday - no change.
Wednesday - no change.
Tuesday - no change.
Monday - no change.
Week commencing 29th November:
Friday - no change.
Thursday - Had no problems sorting out the remaining dialogue positioning issues at work, this may be because I was using XP or because one of the first things I did was increase the dialogue workspace in FNmainBuild(). Began again to work on the rebate calculation by incorporating the old code (although it will subsequently be substantially re-written), not sure whether to have one routine which deals with all the rebate calculation methods or split them up - the former would probably be more efficient, but more complex. While considering this, I decided it would be better to incorporate the two APR methods (Newton's and Bisection) into single routines, so I did this, considerably tidying and shortening the code. I thought about further compressing the simple and complex calculations into a single routine but decided not to, because it's always possible that they will be useful in other programs.
Added messages to the buttons which don't work yet, so that everything in the dialogue is hooked up now, I just have to write the actual routines. Decided to remove the 'Dual' option from the APR/Rebate button as it might encourage users to do the wrong sort of calculations and, while I was at it, changed the name to just DualCalc - as it will be '05 before it's finished.
Decided that I probably need four rebate routines:
PROCcomplexRule78 (as above)
PROCsimpleActuar (which handles Actuarial and DTI Guide methods)
PROCcomplexActuar (as above)
Very roughly implemented the Complex R78/pro-rate routine, still need to be tested and have the results written to the dialogue - Currently greyMode() is opening the APR result too - this need to be corrected for R78/Pro-rata.
However I've hit a non-technical problem ... my colleague in the credit section who approached our IT people to obtain the Office's copy of BBC BASIC forwarded me their initial response which raised concerns about the cost of licensing BBC BASIC and other matters, and questioned whether someone else in the Office, rather than me, might be better placed to produce a solution.
In view of this, particularly the last point, I am concerned about the time potentially wasted working on this so far and have suspended development of the program until decided whether I should continue. Clearly I am not pleased about this and am worried that, if there is a lengthy delay while this is sorted out, the project will be set back by having to later pick up the threads from where I left off.
Wednesday - Working at home because my head feels a bit like I walked into a cupboard door or something. Great start, when I looked at the version I'd sent home it was before I'd finished sorting out greyMode() or done the Deposit stuff - so had to start by doing that again.
Began dickering around with the interface again. Moving the rebate result down has given me room for an extra button and I think I'm going to use it to move the Round/Truncate button out of the APR results. Meanwhile I added what I've labelled the Standard/Detailed button to toggle the logging/printing of additional information.
Also decided that, as in the old programs, further advances should not be available with a Cash price and deposit calculation, so these are now greyed when the user chooses 'Price' in complex mode. Tested the Cash/price and deposit calculations and didn't believe the answers. But when I tried it on the old programs, I got the same answer ... actually, yes, this is right.
Also implemented the rotation of the APR/Rebate button to allow for APR/Rebate/Dual (thought I'd better use 'dual' as that's what I've called the program) and modified the calculation routine to run one, the other, or both (APR first).
Began work on the implementation of complex rebates (Rule of 78 first) by modifying the totalling routine to calculate the time of the last payment in the loan (needed to determine if the user enters a settlement date/deferment which is after the end of the loan). This meant I could also implement the use of 'Final sum' in complex calculations so I did that for APR and modified the dialogue so that it is no longer greyed out for these.
At some point it suddenly dawned on me that a solution to the slightly odd position of the extras panel would be to put the payments (levels and extras) on the left and the advances in the lower position on the right (I think it was seeing them greyed out for Price calculations which triggered this). This prompted another re-vamp of the dialogue - particularly because I realised that the basic payment and timing information needed to be swapped at the top too so that the payment info was still above the regular/number info in simple calculations - and these moves generally required a pretty major overhaul of several parts of the code.
I also moved the Round/truncate function to a 'proper' button on the left but at some point while trying to tidy the results display having done this I hit an annoying snag because the program kept crashing Windows in a rather worrying 'Blue Screen Of Death' way and, when I re-booted Windows sometimes didn't even seem to know it had crashed (no checkdisc on startup etc).
Here's a fairly recent version of the display, the .exe file has not been updated because I need to iron out the BSOD problem first:
Note the dodgy 'period rate' position! Head's still a bit dodgy but I need to get to the Office tomorrow to try and sort out the crashing - I could try putting back the results code from the earlier version there, and maybe increasing the size of the dialogue buffer a bit? Hopefully WinXP at work will be a bit more stable than my old Win98 ... Windows ... stable ... hah!
Note to self - the previous code is on the server as 'DualCalc04A.bbc'.
Tuesday - Bit of an annoying day really. Refined the buttons a little and updated this log at home in the morning before going in and continuing by modifying the dialogue load/save stuff to incorporate the revised layout. Had a migraine in the early afternoon so I couldn't really see the screen for half an hour or so and, when I started work again, my PC wouldn't recognise my password. Our IT people re-set it for me and, when I restarted, the version of the program on my desktop was the one I'd sent from home that morning - all the subsequent 2-3 hours' work had disappeared. Great. It seems our hard drive isn't really our hard drive it's on the network, or overwritten by a 'profile' held on the network - this seems to be so we can walk up to any PC on the network, log on and see 'our' PC setup, nice idea, but really annoying when it goes wrong and has to use an archived setup from a while back. Re-did all the morning's work and then added Loan/Price (as I've called it now) switching. Spent the remainder of the afternoon holding my head, whimpering in a pathetic fashion and sorting out greyMode() to put the switches in the right order (told you I would). Also looked at how the program should actually deal with Cash price/Deposit - it seems ridiculously simply, all I seem to have done in the old programs is subtract the deposit from the total advanced after it had been calculated in the usual way for loan/initial agreements, but thinking about it, that may well be right.
Monday - Very little progress today, re-thought some of the buttons and incorporated some dialogue changes to cope with some of Friday's thoughts.
See the .exe file for the changes in detail but briefly, The calculator and calendar buttons have been removed, they can be accessible through the 'Others' button if and when. I intend to replace these with two further toggle buttons, one towards the top which switches between 'Loan and Initial sum' (the new shorter name for 'Initial payment') and 'Cash Price' and 'Deposit' - it'll probably just be labelled 'Loan' and 'Cash Price'. The second will be above the Log and Print buttons (and, like them, only accessible when results are displayed and will toggle between something like 'Standard' and 'Detailed' to trigger the logging/printing of PV analysis for an APR calculation and Rule78 fractions or whatever for a rebate calculation.
To cope with entering excluded charges I used the 'blank line' at the bottom of the Rebate results, putting APR and Rebate results in separate group boxes with the Rebate ones moved down a line. Then the Extras panel was moved down a line into the vacant space and an 'Excluded sum' text box put in the gap, under the other Rebate entries. Not too sure about the Extras panel being out of line with the others, but it makes everything else fit neatly.
I modified PROCgreyMode() to work with the button revisions and the Excluded sum entry (so it's only available for 'Rebate' calculations) but I also need to:
Aside: had a vague thought that the APR/rebate button should cycle through APR, Rebate, Dual ...
Wrote to the credit team to remind them about getting a copy of BBC BASIC and some test volunteers. They're writing to our IT and Web people about the purchase and distribution issues. Gave them the mail addresses of a dozen or so TSOs who'd contacted me over the past year as possible testers.
Week commencing 22nd November:
Friday - continued with the date stuff but progress is slow. Eventually realised that I was struggling with a fundamental misapprehension by linking the days in a year with the periods pa. Here, in a slightly jumbled fashion, are my thoughts:
The program ultimately needs a time value for the calculations and will need to convert a date to a time in years and days and also, if requested, into weeks, months or some other period. The program already includes a routine from the old DOS programs which calculates the period between two day-numbers in years and fractions of a year where the fraction is calculated according to the DIY value - and taking account of leap years and 365/6 days if that is being used. I have adapted this to use the FIVESIX% flag (which indicate the use of 365/6 days) in the current program. For quick+dirty use of other periods all I need to do is multiply the resulting value by PPA, partly justified by the regulations telling us that there are 12 or 52 periods in a year.
Sorting this out has made a lot of the problems I was having go away - and made the program a lot simpler (and, I hope, easier) to use and code. I was, in fact, able to add the complex APR calculation in about half an hour ... and under my new date -> time conversion regime this includes the 365/6 calculation. In fact I should now be able to cross these off two at a time because the time conversion now automatically copes with 365/6 (incidentally - all the stuff from Tuesday about 365/6 daily calculations can be consigned to the mental rubbish bin now).
Did some basic testing of the Complex calculation. The way I do this with most programs is to set one calculation and approach off against another and check the result - the example I generally start with is the very basic £100 loan repaid by 12 equal monthly instalments of £10: TAP £120, TCC £20, APR 41.3 (EAR=41.299898415). To test that the levels stuff is okay I split the 12 instalments into two or three levels, eg 5, 2 and 5 payments long. This should give the same results. Then I replace a couple of the level payments with extras ... so the middle two payments are now of amount Zero and there are two Extras of £10 at times 6 and 7 ... again I should get the same answers. Checking the advances is a bit trickier but one simple thing to do is stick two loans together ... ie advances of £100 at times 0 and 12 and a level of 24 payments of £10, you can also offset advances and payments ... stick in an advance of £1000 at time 99 and a payment of £1000 at the same time, and they should cancel out giving the same answer ... and so on.
Quickly tracked down and corrected a couple of minor errors with this and now feel I can cross the complex APR stuff of the list.
My next target should be the complex Rule of 78 rebate calculation - my thinking is that knocking this over will also automatically kill off the Pro-rata calculation (the procedure's exactly the same, then you throw the Rule of 78 fraction away and do a simple division instead), and should provide an easy route to the simple Rule78/pro-rata calculations. The structure of the new calculation, although using a PV analysis, will also be very similar ... oh look, what's that?
Dragged what seemed to be the relevant code out of the DOS programs, and made some notes about the variables (included below for my reference):
meth%=1 ... pro-rata rule max : end time of loan last : settlement time lastA : sum of payments made on settlement time paid : total payments up to and including settlement time set : deferred settlement time excl : excluded charges (damn!)
That's it for this week.
Thursday - for the record, this is the thirtieth anniversary of my joining the OFT! Working at home today and tomorrow. Okay, addressed the two outstanding problems from yesterday:
Nope, can't switch the X off by any obvious route I could think of, so I experimented with adding a close button and a reset button instead - I added the code for three narrow, tall buttons on the right of the results panel, but have REM'd it out for the time being.
Back at the calculation, for one glorious moment though that I was going to be able to produce a working routine in about ten minutes ... but that soon evaporated. I'm still having problems getting my head around how dates and/or 365/6 day calculations are going to be handled. Played around quite a lot with the basic PV and derivative routines but couldn't make my mind up as to whether they should deal with date to time conversion or it should be done in the various calculation routines.
I still think there's something basically wrong in how I'm dealing with dates. Looking at the code of the old DOS programs, I stored all times as times and a flag indicating that the user had entered that time as a date. This could create some minor discrepancies when the user printed or re-entered dates, because they had to be converted back to dates from the stored times based on the Periods pa and Days in a year settings. I have tried to avoid that here by storing the actual daycodes when the user enters a date - that way they'll always get the same date back - but this means that the date has to be converted to a time during the course of the calculations ... hmmmm, actually that shouldn't be so difficult if you know the date and the other factors, but there are two 'factors' and only one user input for them?
Started to scribble a 'truth table' of the possible combinations and came up with something like this (rdate=relevant date):
There's still something missing here.
Some other random questions have also occurred to me:
Wednesday - took a look at the compaction stuff this morning after sleeping on it. Managed to sort it pretty quickly so the routine works for all elements and returns the correct last valid element, including where there are none and where it's the last one. This broke the panel display routines because they need an index of the top element in the panel minus one - and zero where the last element is full so the panel wraps around to the start again. Wrote a small function called topTen() which produces the right index from the value now returned by FNcompact().
Right, back to that pesky complex APR calculation routine ...
... Or maybe not, because I got sidetracked into improving the 'catch net' stuff so that would not completely reset the calculator anyway when you clicked close and then Cancel. Improved this somewhat so all the dialogue stuff is initialised correctly and re-initialised when the user cancels - but it still needs to do something about retaining the dialogue contents. I am planning to use some sort of XML format in the final Save/Load routines (so advanced users/other programs can write their own calculation files and get DualCalc to run them ... thinks: and print/log the results, and 'chain' another calculation) but maybe a simple save/load of the strings in the dialogue would be better here.
Meanwhile, back at the calculation, I copied over the starting section of the simple APR routine and produced a routine PROCtotalPays to sum the TAD (total advanced) and TAP for the loan data and calculate the TCC. Currently, at the end of the day, there are some snags:
Tuesday - took some time at home this morning to dig out and go right back to the original TRURATE code to see if I could spot the solution to the 365/6 Newton problem there. Nope, I modified it to do a 365/6 calculation and it promptly fell over.
It seems - shock horror - Newton simply won't deal with this. The only option I can think of is to use Bisection in these cases.
When I got into work I amended Newton's method to detect x going -ve and give up so Bisection could take over. Then Bisection fell over with the same log range error - Arrghhh!. It seems that the problem is that, to allow Bisection a wide sweep, I was using the range -1 to 2, introducing -ve x values again. So, I cut the range back to a more normal 0 to 2 and the program finally spat out an answer.
What concerned me now was that the answer it produced, although clearly in the ball park, seemed to be quite a bit different from the answer produced by Newton's method using 365.25 periods, so I did a bit of experimenting:
Although the fact that I could do this made it apparent that the program was not insisting on a relevant date for the 365/6 calculation, as it should, the close correspondence between the 366 day calculation and the 365/6 one made me more comfortable that it's doing the right calculation, but thankfully not the same calculation.
Loads of minor problems when I tried to introduce the Relevant date into the calculation - but mainly me not paying enough attention to the times I should actually pass to the routines. I think it's all okay now, it unsurprisingly produces the same result as in the table above with a relevant date of 1/1/2004 - I wouldn't expect to see any difference over a 10-day period. So, a second calculation crossed off the list below.
At some point I also added a catch net for the user clicking on the close icon - previously the program just closed down, now it asks of you're sure first - but it doesn't yet do anything to preserve the user's data, so they get back to an incomplete display. It at least needs to read the current data with FNcheck and write it back if the user cancels the close action. Also had the thought that the calculator might write the current calculation to disc when it closes and re-load it on startup, so the user comes back to the same state. This started me having thoughts about network use and multiple users (shudder - a lot of work in the DOS version). At present I'm working on the basis of one PC, one copy, although it might be possible to do something simple with a shortcut to a network copy and 'Start in' set locally so that the CSD (sorry a RISC OS term: 'currently selected directory') can be read on startup and all the load/save stuff done relative to there ... do this later!
Started - again - to work on the next calculation (complex APR) and thought it would be a good idea if the array compaction routine returned the value of the last valid entry in the array - which the complex routine could use as a stop point in reading the data. However I discovered the compaction stuff was still a little broken and didn't cope with entries in the last element of the array. Need to fix this before proceeding.
Monday - Further developed general routines for extra payments which handle 365/6 days too and hit quite a big snag. As I only have simple APR calculations available at present I tried a basic £100 loan repaid by 12 daily payments of £10 and it wouldn't work - Newton's method fell over with a 'log range' error because you can't raise -ve numbers to fractional powers and the first iteration was pulling up an x-factor of about -8 (it's normal between zero and one - yikes!)
Spent a lot of time looking at this and checking back over the original formulae to see if I'd cocked something up - couldn't find the problem but tidied up the simple APR routines and incorporated the general extra routines FNextraPV() and FNextraDV() in the process. Also realised that I should use the extraPV/DV routines to deal with 365/6 days in the levelPV/DV routines.
Gave up for a while and took another look at the business about displaying the current mode (I don't really like having the info down on the bottom line). Decided on - and implemented - an alternative where the significant buttons: Simple/Complex and APR/Rebate (also T/R); display the current status rather than their function - and these are in square brackets to indicate the distinction - haven't done this for the Calculate/Enter button though - I think it's pretty obvious how this works and doesn't need it.
Still need to solve the Newton problem for 365/6.
Week commencing 15th November:
Friday - More thinking than coding today, I have however written some more general APR levels routines (FNlevelPV and FNlevelDV) which will deal with any level, not just the first, AND will cope (I think) with 365/6 days. I've used these instead of FNequalPV and FNequalDV in the simple APR routines and all seems okay.
Thursday - Only a bit of fiddling about today - added a 'Truncate/Round' button (just after the APR box, labelled T or R) and amended the greyMode() procedure to switch it. I'd sort of forgotten about truncation, it was linked to 365 days in the old programs and I think I was assuming it would be somehow here too? Think I've sorted out some of my concerns about date handling, albeit only in my head. Went through and tidied up the libraries a bit - and the 365/6 days routine.
Also compiled another depressing list, this time of other bits of the program/project to be completed. This is quite similar to the button list but in order of priority:
(the last two are deleted because I've decided not to do them)
Wednesday - had some stuff to do on my 'real' job today so almost nothing changed. Decided I didn't like the mode indicators in the corners of the dialogue so I've combined them and put them in the bottom right corner. Started to look at an equal APR calculator for 365/6 days, this will probably have to be an entirely separate calculation routine which copes with both Newton's and the Bisection method, didn't get very far.
Realised I had blocked off perfectly legitimate negative APR calculations, so I changed the error message to a warning with OK/Cancel buttons.
Thought I might make a list of the calculations needed - just to depress myself (although to cheer myself up again, I've decided to cross out things here as I do 'em):
[TO DO] Simple Actuarial Rebate - awaiting revised Regulations
(This list has been halved now by removing duplicate 365/6 day entries - see Fri 26th Nov)
Tuesday - Introduced the buttons mentioned yesterday and then got them into a (more) logical order. Sorted a glitch in the Simple data display (the Regular and Number values weren't written back and this lead me to looking again at the mode switching (parts of the dialogue being enabled/greyed out). Pretty much re-wrote this from scratch, this time ensuring that all the appropriate items are switched on/off for each mode combination - this enabled me to incorporate Calculate/Enter switching and remove the separate routines which did this - much 'cleaner' and more reliable now.
Couldn't see any excuse not to start back on the calculations themselves now, but when I did I discovered there was something wrong with the Tidy routines. Although the array compaction worked fine for valid values dispersed across the array it didn't seem to want to remove invalid ones (zero advance or extra amounts, or zero length levels). While fixing this, I also implemented a vague idea I had a few days back that the display should go to the next free row (rather than back to the first row) after a Tidy. All seems to work now, so really no excuse not to go back to the calculations.
I think my reluctance is, in part, because there are still some things I haven't cleared up in my mind, eg: how should the (currently implemented) Simple APR calculation react when the user chooses 365 or 366 as the Periods pa? Daily regular payments is probably a daft input anyway, so do I spend time writing a routine which calculates the APR (and Rebate) on an extras (one payment at a time) basis? It might make more sense to just get the program to say 'Hey! Daily repayments? Are you nuts? Ultimately, I think I am going to have to ask our lawyers how to approach this.
As the user interface is provisionally finalised (is there such a thing?) now, I thought I'd end today's log with an image:
Monday - Not that much progress today but I did add a system where the Simple/Complex and APR/Rebate status is displayed in the bottom corners of the dialogue to give an independent indication of what's going on. Also finished the 'writing-back' stuff so each data item is put back in the dialogue in the right format as it's validated.
There seemed to be something wrong with the APR calculation still, I was looking for examples where it would switch to Bisection and seemed to be finding them far too easily - and Newton's method was just going way off track (PV error = £???E24 or bigger) rather than just getting stuck. Deleted and then re-wrote the routines and it works now.
Had a few more thoughts about the final look of the program and the facilities it might offer - came up with a provisional 'final' set of buttons/functions as follows (n/f = non-functional at present):
These seem a bit of a rag-bag at present and need more logical ordering.
Our IT people confirmed that they block .exe files (but don't tell anyone) so I'll have to avoid sending them through the OFT mail system in future (or use my web mail account which seems to work fine). They were very helpful and have agreed to look at this so people are warned if their mail is altered and to consider the problem of mailing the final program.
Week commencing 8th November:
Friday - implemented most of the list at the end of Thursday. There are now two buttons, initially labelled 'Simple' and 'APR' which toggle to 'Complex' and 'Rebate' when you click them. There is also a button which says Calculate while you're entering the data and 'Enter' while the results are displayed.
Still tinkering with the validation/result reporting system. Sums of money now all right-adjusted and displayed to 2dp as soon as the program reads them, so the decimal points all line up, rates remain left adjusted and times centred to help distinguish them. I think I also need something to write back values to the combo-boxes after they are read and validated.
Didn't bother to check for INVALID-> anywhere in a string, the point was to stop the program repeating it's own labelling, if the user's daft enough to actually type 'INVALID->' somewhere else themselves ... well duh.
decided to put the latest version on the intranet so that other can keep track of it, mailed to let them know it's there. Re-incorporated the libraries with the program source for the time being - this makes it easier to track and correct errors and also means that the compiled version can be run from the intranet because it all downloads in one file.
Have some doubts about the Simple/Complex and APR/Rebate buttons - just because they display what they will switch you to, not what you're currently doing - so, eg, when you're carrying out a Simple APR calculation the only thing you can see on screen is 'Complex Rebate' on the buttons ... hmmm.
Bit of a diaster when I got home. Instead of my mail with the latest version attached I got an empty .zip file and a nice little message saying:
*********************************************************** The attachment DualCalc04 12-11-04.zip has been removed from this message by the OFT's mail system. It is against the OFT's Security Policy for files of this type to be e-mailed. ***********************************************************
... so I couldn't update this log or progress anything for a couple of days. I've asked our IT people why - although I can guess it was because there was an .exe file in it this time, which makes me wonder how we're going to mail the final program to people.
Thursday - stayed at home again and seemed to get a lot more done. Determined to get it to actually do something useful, I dug out the formulae for equal instalment APRs and adapted them for the program. Initially the results were nonsense but I seemed to have some extra brackets in the formulae and sorting this out gave me the right answers for some basic examples - not sure why I didn't get a 'parenthesis error' though. Introduced other formulae to calculate period, nominal etc. rates and was getting answers okay - albeit PRINTed on the program screen, rather than in the dialogue. Woohoo! The calculator actually calculates something.
Needed to re-visit the validation system I worked up yesterday. Changed to one where a central routine reads and validates all the displayed data using INVAL% and ERROR 100 whenever the user hits a relevant button - so far these are Tidy, APR or any of the VCR buttons. This seems to work well but I discovered that 'INVALID -> ' got repeatedly added to the entries (because 'INVALID -> ' is an invalid entry - very logical see?) and had to detect and fix this. Adopted a system where a routine 'cleans' entries before they are validated and evaluated, stripping any excess spaces front or rear and the 'INVALID-> ' string off the front. Also introduced some calculation validation - things like zero rate loans, no payments, no advances, and a simple message box as the easiest - and least annoying - way to report these.
Looked at the code for the old APR programs and realised that the more advanced one had a system where it switched to Bisection after 50 iterations if Newton's method hadn't got to an answer (because it was stuck). Wrote a Bisection version of the iteration and a system to check and switch - and to fail the calculation if Bisection didn't hit an answer after (I think) 100 goes. The iterative routines report their progress in the info line at the bottom of the dialogue but it's all too quick to see so I'm thinking about introducing a small (1/4 second or something?) delay to make it visible. there were small discrepancies between the Newton and Bisection results so I took a look at 'precision' in the BBC BASIC help file. It seems the new version provides an option to use 64-bit (as opposed to 40-bit) reals working through the Pentium (or in my case AMD) co-processor. I added a *FLOAT64 command to the start of the program and upped the precision checks in the iterations from 10E-9 to 10E-12 which ironed out the discrepancies - apparently this introduces some issues with reading reals saved in files using FLOAT40 (I suppose they're 5 bytes instead of 8) but I'll worry about that if it arises.
Started to add a results box and some more items for results to the dialogue. Annoyingly there's one more APR result than for rebates so it leaves a gap. Played with the layout until I was happy and then decided to use text boxes - rather than static text - for the result values, because they look a bit clearer and - importantly - give the user an opportunity to cut the values to the clipboard if they want to use them in a document or something. Realised that they were all being written in &90A format so wrote a routine to allow control of how they were written.
Started to play with the control of results display - greying out the input items when the results are displayed and vice versa. Realised I could save a button by having a single Simple/Complex button toggle between the two options and adapted the simple and complex routine into a single mode routine to do this - it needed a switch so wouldn't toggle unless told to. Also realised I could do something similar with APR/Rebate and a Calculate/Enter buttons.
Other things to do:
Wednesday - working at home from about 7:30 and immediately discovered on my slow machine that there was something wrong with the greying stuff - the boxes seemed to get enabled/greyed about three times when the program started instead of once. Sorted this out and then looked at improving the way the VCR buttons work - and got them to cope with varying maximum numbers of advances, levels, extras, in case I implement this as a user configurable option.
Shuffled some boxes around at the top of the dialogue again and I'm happy with it now, also looked at the variables I've used to landmark some of the elements of the dialogue (all the buttons, boxes etc in a dialogue have a unique number so you can refer to them in the program, know which one was clicked and so on. I don't store the number of every one though, just certain 'landmark' ones like the first button, the first text box, etc and, as I've built the dialogue in a logical order, I know button2 has number button1 + 1 and so on) I tidied up the landmarks a bit and introduced specific variables to hold the numbers for the drop down combo boxes as this made them easier to handle in the CREDLIB1 routines.
I also added 'DTI Guide' to the rebate methods drop-down (although it's initially hidden and you have to scroll the drop-down to see it). The intention is that this will trigger carrying out the actuarial calculation but ignoring the 'Original APR' entry, calculating the APR for the described loan and using that instead.
Added a few more buttons - including 'APR' and 'Rebate' buttons to start the calculation ... as I'm pretty much at the end of my initial 10-day estimate, maybe I should stop mucking around with the interface and actually try to get it to do a bloody calculation!
Started with a simple APR calculation. Immediately realised that I needed to look at the detection of erroneous input in more detail. I've settled on a system which combined a global variable INVAL% to flag an invalid entry (it's set to FALSE before chunk of data items is read from the dialogue and, if it's still FALSE at the end, they're okay) and some local errors (all ERR number 100 but with various ERR$). The program retain the user's duff input but adds 'INVALID=> ' on the front of it, so if they type 'Wibble' in a text box, after it's read it says 'INVALID=> Wibble' which gives the user a chance to see what's wrong and correct it.
Began to progress the simple APR calculation but needed the formulae etc - so I've added the APR, Rebate and Date Calculation technical papers to the temporary help material.
Progress seems very slow.
Tuesday - Started at look at the way the program might provide the 'simple' input Lisa had suggested. Initial thought: perhaps provide 'Simple' and 'Complex' buttons. The simple one would grey out all the payment options apart from Loan, Initial, Final and the first Level. The complex one would switch it all back on again (perhaps apart from the 'Final' entry - which could be a payment made at the same time as the last payment in the level. I could even change the column level headers to 'Regular (£)', 'Number' or something.
Implemented this and showed it to Lisa - she thought it was good so I'm sticking with it. I spent the rest of the day moving the stuff in the dialogue around so it looked more logical - the three blocks along the top strip now deal with timing, payments and settlement respectively (although the settlement date is in the timing bit ...) and this now conveniently places the payment details above the Regular/Number entries in simple mode. Pretty much had to re-write the simple/complex greying routines again as a result of this.
Monday: I was still quite concerned about the time the program was taking to tidy up data. I tried it on my slow old PC Card at home and it was taking something like 40 seconds! I added some PRINT statements to the code and realised what I'd done: the routine searched down the arrays for zero or invalid entries and, each time it found one, moved all the ones below up one in the array. With 1,000 'extras' this meant is was on a sliding scale of 1,000 down to 1, moving stuff 1,000 times - half a million moves in all! I had to find a better way to do this and developed something where the arrays were scanned just once, with a pointer remembering where the next free slot was. As this is, for 1,000 extras, 500 times more efficient, the speed is no longer a problem.
It occurred to me that the user might try to add something to the input while a reset or tidy was going on, so I've added a 'grey out' routine to switch them off while this is going on. Not terribly important with faster machines, you can hardly see it happen.
I realised at some point it would probably be more appropriate if the user could enter details of the method of rebate calculation to be used, or the deferment to be used, in a drop-down combo-box - as I'd already used for the period entry. I wrote the additional code, based on the period stuff, to initialise and interpret these and added the boxes to the dialogue, moving other stuff down to make room at the top. As this gave three rows for rebate info and only two for loan/initial and relevant date/periods, I arbitrarily added a 'Final payment' box (not sure what to do with this yet) and, more purpositively, an 'Original APR' where the user will enter the original agreement's APR for the version of the calculation the Regs seem to require at the moment (as opposed to DTI's version).
Week commencing 1st November:
Friday - I, along with a lot of other civil servants, am on strike over the government's plans to axe thousands of our jobs, increase our retirement age, reduce our sick pay benefits and generally screw up our lives by trying to renege on the contracts they originally made with us. A bit of politics there ... back on Monday.
Thursday - implemented the ideas below, added 'Loan' and 'Initial' (down payment or deposit) text boxes to deal with Lisa's second concern - now you should be able to describe a loan by just these two items and any levels - and I moved all the stuff in the dialogue around a little so it looked neat with these changes. Showed it to Lisa in the afternoon and she seemed happy with the changes. This is what it looks like at the moment:
Wednesday - engaged in my 'proper' job most of today. In the evening on the train home it occurred to me to think about how users might want to amend the data while entering it. Luckily, the tidy system already gave them a way to delete entries - set the amount of advances or extras, or the number for a level to zero and they will be tidied out of existence, either at the click of the Tidy button or before the calculation starts.
Also, for advances or extras the order in which they appear in the data is immaterial (although I have put the idea of sorting them by time when they're tidied on my mental 'consider this' list). Levels however were a different matter, because the order in which they appear is important - so what if someone wants to add a level they've missed?
The solution I came up with is to add a series of 'insert' buttons down the side of the levels panel which, when you click on them, moves that level and all the subsequent ones down a row so you can enter a new one.
Tuesday - my Birthday! I got a few other things working and then decided it would be a good idea to show a couple of colleagues in the credit team what I'd done so far and see what they thought. Edward, who basically took over the job I used to do, was quite positive but he hasn't had much opportunity to use the old programs. Lisa, who has more experience with calculations, had a number of comments which seemed important, mainly:
A bit disappointing because I could see that, although I had most of the tools to do what she'd suggested in the current code, I would have to unpick a lot of it from the system where all the data appeared in one panel. However, I value her opinion and, although I started by saying that I'd have to continue down the current route and look at her suggestions later, the more I thought about it the more I realised it would be better to sort the interface out first. So, still working 50/50, I started to rebuild the interface so there were three separate panels for advances, levels and extras.
I was also a bit concerned about the time the program took to tidy the input every time a button was pressed. Initially I solved this by reducing the number of extra payments from 1,000 to 500. But with three panels it was also a bit confusing if you did something in the advances panel and the others were tidied too, so I decided to kill two Bs with one S by removing the automatic tidy system and adding a tidy button instead which only does it on demand - the data will however also be tidied before the calculation is started.
Monday - back in the Office, I started to work 50/50 on the program and my normal job. One of the first things I looked at was dealing with converting the stored times/dates to the time periods to be used. I began by looking at what I'd done in the old DOS programs and this made me quite worried - I didn't understand my own code! The problem is, two years since I last looked at it, a program which I once knew like the back of my hand now looks like a lot of neatly laid out but very terse and almost incomprehensible code, written by someone else and with almost no documentation.
There also seems to be rather a lot of code and I started to think about exactly what needed to be covered - maybe I should make a list somewhere. I might have bitten off more than I can chew here and need to revise my 'two weeks' estimate about how long I'd need to spend on it - although I know from experience that these things tend to grind along really slowly at first and then all come together in a rush at the end.
Note the name change. It dawned on me that the DTI approach to the calculation requires a 'revised APR' (okay, there ain't no such thing, talk to DTI) to be calculated for the rebate calculation, so my remit included an APR calculator. Well, if that's the case, why not just make the program a combined APR/Rebate calculator? So. I've changed the working title to one I've used before 'DualCalc' - ie dual APR and rebate calculator. I think I got to version three with this so, in deference to that and retaining the '04' from the first name, I'm now calling it 'DualCalc04'.
I started to look at input validation. Unfortunately, the Windows API seems a bit daft (well, there's a shock) in that there is no way to validate the keys the user types into a text box. In the OS I'm more familiar with (this log is likely to drift into a lecture about how much better RISC OS is at some points, but not now), you can provide a validation string when you set up the equivalent of a text box and only the keys you specify get recognised. With Windows the only option seems to be to accept all keys or to limit the user to numeric keys and - here's the really stupid bit - 'numeric keys' doesn't even include the decimal point, so you can't use it to enter sums of money.
Worse, I want to allow a few other characters for calculations: + - * / ^ ( ) and E, so I'm having to rely on the 'allow everything' option. This causes a problem because the evaluation routine recognises BASIC variables, so if the user types 'wibble' in a box it will look for the variable wibble, won't find it, and generates a 'no such variable' error. There may be a fix for this but, my interim solution will be to post process the characters in the text boxes and remove any invalid ones, so I started to implement that.
As I had already used up five of the ten days we'd allocated to this and only got this far, I also spoke to my boss about my timetable concerns and we agreed that I would do the other five days and then take a look at where we were.
I took a look at the maths on the train home - no doubt impressing the people sitting around me with my algebraic hieroglyphics - and I'm fairly happy that there's nothing new to work on here. The formula:
S = A(x^(n+1)-x)/(x-1)
... works just as well for a level in the new formula, so I can use all the old stuff.
Week commencing 25th October:
Last week, things were a little slack so I spent a few days working at home on the program - provisionally called 'Rule2004' - a term Jim Harper at FISA came up with for the new method of calculation.
It seems likely that we might end up with a suite of programs (as with the old DOS programs) rather than just one, so I decided the first task was to develop some library routines which I could install in the rebate program and any others which come along in the future. Three libraries seemed appropriate:
Bit of a disaster on the first day ...
I'd pretty much finished GENLIB1 when I realised that putting stuff in libraries means it won't be 'crunched' (a BBC BASIC term which means that all the unnecessary spaces, long variable names, short program lines etc in your program code are removed or bunched up to save space and make it run a bit faster). In BBC4Win (I'm not gonna keep typing 'BBC BASIC for Windows') the final Windows program is a combination of the interpreter (the program which understands the BASIC code) and your code in a single .exe ('executable') file. CRUNCHing is an option when you produce this so, it only happens to the main program code, not the libraries in separate files.
There may be a separate CRUNCH program available, but I thought Ah-hah, all I need to do is compile a library, find where the crunched BASIC code is embedded in the .exe file, yank it out again, and I'll have a crunched library!
I started to write a program to do this and, because it had most of the useful stuff in there, based it on the GENLIB1 library, cutting out all the routines I wouldn't need. Stupidly, at some point I hit 'Save' instead of 'Save as', and over-wrote my shiny new library with a file which only contained about 10% of it.
So I had to abandon the cruncher for the time being and spent the best part of the next day re-building GENLIB1 - not an auspicious start.
The rest of the day and the third day was a bit more progressive ... progressful ... I made more progress. I managed to build a dialogue with text boxes to enter the time periods being used, the relevant date (start date) of the agreement, and a gadget for entering advances, levels and extras (these are terms from the old programs, they refer to different ways of describing the money changing hands in the loan) which consisted of three buttons and two columns for amounts and times ... what am I doing? Here's a picture:
When you clicked on the advances, levels, extras buttons the contents of the columns were read into arrays in memory, then the column headings underneath changed as appropriate and the corresponding data was read out of memory and into the columns - so you could switch between the different data types and the display would update appropriately, remembering any changes you'd made. Only 10 lots of data was displayed at a time but the 'VCR' buttons underneath could be used to page through more, ten at a time, again storing any changes made first.
I'd also written some routines so that you can type something like '25/11/2004' into one of the time entries and it's correctly interpreted as a date, checking for inappropriate ones etc. and one byte flags in memory also record whether an entry is to be interpreted as a date or time.
I also started to think about the less logical ways a user could use the interface I was presenting - for example by not filling in the text boxes consecutively starting from the top. So I added a system where clicking any of the dialogue buttons would cause the program to 'tidy' the input, removing any advances or extras with zero amounts or any levels of zero number and then closing up the gaps so all the entries were placed sequentially from the first.
Quite pleased with the overall result, but a bit concerned about the rate of progress, I went back to work.
About two or three weeks back ...
I had a formal meeting with the credit team to sort out a few things. I haven't seen the note yet but we mainly agreed that:
We agreed that I would devote about two weeks to this and, as I don't work on credit now, I cleared this with my manager.
First thoughts ...
When this was initially raised my first thought was that the old DOS programs could actually do this calculation already - the formula used is not the one in the new Regulations but it is an equivalent giving exactly the same answer (although I am uncertain about how the rules on deferring the settlement date have changed) - so there probably wouldn't be too much involved on the maths score, it would just be a question of updating the interface to Windows ... hmmm.
BBC BASIC for Windows - A shameless advert
I can't emphasise enough what a useful environment BBC BASIC for Windows is for doing something like this. The old credit programs are written in BBC BASIC(86) - a DOS BBC BASIC interpreter - and its author, Richard Russell, has since brought out a Windows version.
Like most people, I'm not someone who can write enormously complex programs in assembler or grasp concepts like object oriented programming well, but I was around at the time of the original BBC programme designed to teach computing to the general public and, with the help of a BBC Micro and BBC BASIC, learnt a lot of the basics (ha ha) of programming. By the time the BBC Micro reached the end of it's life cycle, I could pretty much make it do what I wanted. With BBC BASIC(86) for DOS I eventually got to pretty much the same position with DOS-based PCs.
A Windows-based PC, however, was another kettle of fish. Unless I resorted to DOS, it was just a piece of consumer electronics on which I used programs other people had written. I could no more write Windows programs to add my own facilities than I could, say, rewrite the way my VCR displays its menus.
BBC BASIC for Windows however, is starting to give back some of that control. It will (with a little coercion and some routines provided by Richard) interface with the Windows API (applications protocol interface) so you can do stuff like menus, button bars, dialogues etc. I still struggle with some aspects of this, but I have produced quite a few programs, file utilities, HTML editors etc, which use a dialogue as their main interface with the user, so I know I can use it to produce a new Windows-based way of getting the calculation data input and the answers output.
What's more, it's only 30 quid, comes on one floppy disc, and Richard is very helpful if you get stuck - try emailing Bill Gates asking how to do something in Visual Basic and see if you get an answer (of course that's after you've spent several hundred quid and installed the contents of four or so CD-ROMs on your PC).