A while back, another member of the MoHPC forum mentioned a program he'd written for the HP-41C that allows the user to manage multiple alpha registers. I responded saying that I had written something similar many moons ago that behaved like a LIFO (last-in-first-out) stack rather than an indexed array of datasets and said that I'd look it up.

I have no idea whatsoever what I did with my little utility so I decided to rewrite it, purely and simply. So here it is.

NB: This program creates and manages a data file in Extended Memory called "ASTACK". If you already have a file of that name, it will be deleted! Note also that running these programs uses Flag 01 and trashes registers R07-R10. Finally, since this uses Extended Memory, you will need to run this on a 41CX or SwissMicros DM41, or on a 41C or 41CV with the "X-Function" module.

The size of the data file created in Extended Memory depends on the depth of the alpha stack that you want to create. Two registers are needed for a header in the file and four registers per stack level are needed. So, if you want a stack that's 6 levels deep, for example, then you'll need room in your Extended Memory for a file that's 2+6*4= 26 registers in size. You'll actually need 28 registers free because the calculator also steals 2 registers for its own internal housekeeping when you create a file in X-Mem.

The three utilities provided are "ASINIT", "APUSH" and "APOP".

ASINIT

Run this with the depth of the desired stack in X, The '41's own error detection will prevent you from creating a file that's too big or from running this on a machine with no "X-Function" module installed (remember, the 41CX and the DM41 have this module baked into their ROM).

APUSH

This will save the current contents of your alpha register onto the alpha stack and return 0 in X, unless the stack is already full, in which case you'll get -3 back instead. If the alpha stack hasn't been initialized (by running ASINIT) then you'll get -1 back in X.

APOP

This takes the string on the top of the alpha stack and transfers it into the '41's alpha register, removing it from the stack. If all went well, X will contain 0 after returning from this program. If the alpha stack has not yet been initialized then you'll get -1 back, or if the stack was already empty (everything already popped off it) when you called APOP then you'll get -2 back.

Software provided, as usual, as a text listing, a .raw file and a PDF with bar codes.

Edit: I wrote something similar for HP-42S/DM42. This machine has no Extended Memory but can store register data into a matrix. That's exactly what we do with this version.

Grab the listing here: astack.txt and the .raw file for DM42/Free42 here: astack.raw

The "N Queens" problem is a puzzle where you take an NxN chequers or chess board (it's usually 8x8 but this works for the general case) on which you have to place N queens in such a way that none of them threaten or are threatened by any of the others.

Reminder: in the game of chess, a queen can move as many squares as she likes horizontally, vertically or diagonally but cannot jump over any of the other pieces on the board like a knight. This means that any piece in her direct line of sight on the same line, in the same column or on a diagonal to her is fair game.

With this in mind, it is clear that there is only one solution to the problem on a 1x1 board, i.e. a single square (you just plonk a queen on it and you're done), and that there is no way to organise two queens on a 2x2 board or three queens on a 3x3 board without them threatening each other. For a 4x4 or greater board, there is more than one solution.

I thought I'd have a go at solving the general case on an HP-71B and the program listed in its entirety below does just that. There's also a brief video of the 71B in action finding all the solutions to the problem for a 5x5 board in just over 30 seconds.

Here is a line-by-line explanation of the algorithm:

10 DESTROY ALL @ DELAY 0

Clear up any variables currently in memory and tell the 71B not to waste time pausing after displaying something on screen. This is going to be slow enough as it is :)

20 OPTION BASE 1 @ STD

I want the elements in the array that I'm creating later to be numbered from 1 onwards rather than 0, and we need integers to be displayed with no decimals or we're going to get a string overflow (and something far too long to display on screen) in line 200.

30 INTEGER R,C,S,T,F,N,K
40 REAL W

OK, let's set up a few variables.

R and C are going to represent the row and column of the square on the board where I want to see if I can place a queen.

S is the size of the board.

T will be used as a counter while I'm seeing if a queen that I place on the board is being threatened by one placed earlier on a row with a lower number.

F is the running count of solutions found so far.

N is the number of nodes of the puzzle examined so far. Each time a queen is tentatively placed on the board, this is a puzzle node.

K will be used as a counter while building the string representing the solution that was found.

W, the only real variable used here, holds the time of day when the run was started for most of the life cycle of this program. At the end it is replaced by the time, in seconds, that it took to find all the solutions to the puzzle.

50 INPUT "Board size 1-9: ";S
60 IF S>9 OR S<1 THEN 50

Ask the user what size board to work with. Anything below 1 makes no sense and anything above 9 will just take far too long to solve. It already takes about 50 minutes to solve for an 8x8 board...

We start by creating an array of integers B() with as many elements as there are rows on the board. This array will hold the number of the column where there is a queen on each row. We then display something on screen to let the user know that we've started crunching numbers. Depending on the size of the board we're working with, it can take a while to find the first solution.

We then initialize the row counter and the running counts and we make a note of the time when we started.

90 R=R+1 @ IF R>S THEN 190
100 C=0

This is the point in the algorithm where we move on to the next row. If we've only just started then the "next" row is actually the first row. Otherwise, we come here when we've successfully placed a queen on the board and we want to try and place one on the next row.

However, if we were already on the last row of the board and we try and count beyond that number, then it means that we just placed a queen on the last row, i.e. we found a solution! In this case we go off to line 190, where this situation is handled. If not, then we reset the column counter so that we can look at all of the squares in this row one after the other.

110 C=C+1 @ IF C>S THEN 170

So, we move on to the next column. If we've only just started looking at the current row then this is the first column. Otherwise it means that we couldn't place a queen in the previous column or that we could, but we're looking for solutions that involve placing her on a different square in the same row.

However, if there are no more columns, i.e. if we attempt to count beyond the size of the board, then it means that we need to backtrack a row and start looking for solutions with a queen in a different column of the previous row. This is handled in line 170.

120 T=0
130 N=N+1

We're still on the board so now we need to see if a queen placed in the square identified by R and C is safe. We're going to use the variable T as a counter iterating through all the rows previous to R to see if a queen in any of those rows would threaten one here. We also increment the variable N to indicate that we've found a new node to examine.

140 T=T+1 @ IF T>=R THEN 160

We're going to look at the next row now, but if the next row happens to be this row (R), then it means we've found no threat coming from previous rows and a queen placed on the square that we're looking at right now is safe. This is handled in line 160.

150 IF B(T)=C OR ABS(B(T)-C)=R-T THEN 110 ELSE 140

This is where we determine if the queen in row T is a threat to us in row R, column C.

Remember, the array B() holds the column numbers of the queens in each row. Thus, B(1) holds the column of the queen in row 1, B(2) that of the queen in row 2 etc. B(T) is the column of the queen in row T. If the queen in that row is in this column (if B(T)=C) then she would be a threat to us. Similarly, if she is removed from us by as many columns as rows (if the absolute value of B(T)-C is the same as R-T) then that queen is on the same diagonal as us and would be a threat. In either case, we can't place a queen on this square, so we go back to line 110 where we look at the next column.

If, however, the queen in line T would not be a threat to us then we can look at the next line by jumping back to line 140.

160 B(R)=C @ GOTO 90

If we make it here then it means that we can place a queen on row R, column C. How do we do this? By setting the relevant element of the B() array, B(R), to the column where we're placing the queen. We then go back to line 90 so that we can move on to the next row.

170 R=R-1 @ IF R=0 THEN 230
180 C=B(R) @ GOTO 110

We came here from line 110 when we tried to look at a column beyond the last one in the current row. This meant that we couldn't place a queen anywhere (else) in this row, so we have to backtrack a row and continue the search. So we start by decrementing the current row counter.

However, if we were on the first row anyway and we can't place a queen in that row now, then we have reached the end of the puzzle. There are no more solutions possible! This is handled in line 230.

If we were able to backtrack, then we set the column counter C to the column of the queen in this earlier row and we go back to line 110 so that we can look at solutions with a queen in the next column.

190 F=F+1
200 F$ = "Found " @ FOR K=1 TO S @ F$ = F$ & STR$(B(K)) @ NEXT K
210 F$ = F$ & " (" & STR$(F) & ")" @ DISP F$

We wind up here if we found a solution.

So, we start by incrementing the running count of solutions found. Lines 200 and 210 construct and display a string indicating the solution just found and the number of solutions found so far. It ends up looking something like:

Found 53142 (10)

The five digits after "Found" indicate that this was a 5x5 puzzle and that the tenth solution found (indicated by "(10)" at the end of the line) was to place a queen in each of columns 5, 3, 1, 4 and 2 of rows 1 to 5 respectively.

220 R=R-1 @ GOTO 110

Remember, we got here by incrementing R beyond the total number of rows in the puzzle (see line 90)? Before we go back into the puzzle to look at the next column of the last row, we need to decrement the row again to bring it back within the bounds of the problem. We then go back to line 110.

230 W=TIME-W @ IF W<0 THEN W=W+86400

This is the end of the puzzle!

We find out how long it took to crunch through all of the possible solutions by subtracting the time of day now from the time of day when we started in line 80. There is, however, one pitfall to this. TIME is a function that reads the clock to give you the time of day in the form of the number of seconds elapsed since midnight, to the nearest 100th of a second. This value can therefore be anything from 0.00 (dead on midnight) to 86399.99 (0.01 second before midnight). Reminder: disregarding leap seconds, there are 60x60x24=86400 seconds in a day.

What happens if you're like me and you sometimes leave a test to run its course overnight after you've gone to bed, resulting in the test starting before midnight and ending after midnight?

Say the test starts at 11:50pm and finishes at 12:10am. 11:50pm is 10 minutes (600 seconds) to midnight, so TIME will return 86400-600=85800. Come 12:10am and the end of the test, TIME will return 600, so TIME-W will be 600-85800=-85200. Congratulations on the negative test duration. You were able to complete the test 23h and 40 minutes before you started...

The HP-71B is a great machine, granted, but it hasn't quite mastered time travel yet. If the duration computed is negative then we compensate for the date flipping over by adding the number of seconds in a day to the result we found. -85200+86400=1200, which looks more like the 20 minutes expected.

We construct and display the string indicating how many solutions were found and how many nodes were examined to find them.

The short video below shows all of this in action, and the complete listing is provided below that.

As shown at the end of the video, the variable W contains the time in seconds taken to complete the puzzle, F is the number of solutions found, N is the number of nodes examined and F$ indicates the last solution found.

10 DESTROY ALL @ DELAY 0
20 OPTION BASE 1 @ STD
30 INTEGER R,C,S,T,F,N,K
40 REAL W
50 INPUT "Board size 1-9: ";S
60 IF S>9 OR S<1 THEN 50
70 INTEGER B(S) @ DISP "Working..."
80 R=0 @ F=0 @ N=0 @ W=TIME
90 R=R+1 @ IF R>S THEN 190
100 C=0
110 C=C+1 @ IF C>S THEN 170
120 T=0
130 N=N+1
140 T=T+1 @ IF T>=R THEN 160
150 IF B(T)=C OR ABS(B(T)-C)=R-T THEN 110 ELSE 140
160 B(R)=C @ GOTO 90
170 R=R-1 @ IF R=0 THEN 230
180 C=B(R) @ GOTO 110
190 F=F+1
200 F$ = "Found " @ FOR K=1 TO S @ F$ = F$ & STR$(B(K)) @ NEXT K
210 F$ = F$ & " (" & STR$(F) & ")" @ DISP F$
220 R=R-1 @ GOTO 110
230 W=TIME-W @ IF W<0 THEN W=W+86400
240 DISP "SOLUT:" & STR$(F) & ", NODES:" & STR$(N)

The program downloadable from this page is a numerical solver. It attempts to find the zeroes of a function $f(x)$, i.e. it attempts to find $x$ such that $f(x)=0$

There are several methods for this. One that requires little computing power is Newton's Method, or the Newton-Raphson method, a description of which can be found on Wikipedia.

We have no way of knowing the exact value of $f'(x)$ on the HP-41CX used here because that machine has no symbolic math capabilities, so we calculate an approximation of $f'(x)$ by taking a small value $\epsilon$ and calculating:

This then allows us to calculate the next value of $x$ to use and display so that we see the calculator homing in on the zero that we're looking for:

\[ x_{n+1} = x_n - \frac {f(x_n)} {f'(x_n)} \]

Once we find a value of $x$ such that $|f(x)| \lt \epsilon$, we stop and that value of $x$ is deemed to be a zero of $f(x)$.

The same $\epsilon $ is used here as the small value added to $x$ to calculate $f'(x)$ and as the threshold below which we deem $f(x)$ to be zero. It is calculated according to the display precision of the HP-41CX. The calculator's flags 36-39 are examined to ascertain how many significant figures are displayed and we retrieve the digit after the last used FIX, SCI or ENG command. E.g., if the calculator is in FIX 4 mode then we get a 4 back. Let's call this number $p$ for precision.

We then calculate $\epsilon = 10^{-p} $, so the higher the display precision, the greater precision we seek from the algorithm. Similarly, if less precision is required for the display then less precision is demanded from the algorithm and it can complete after fewer iterations.

It may well be that the algorithm is unable to converge on a zero because of the nature of the function studied. It could be constant or it could send the algorithm off on a wild goose chase. There's some discussion of such cases on the Wikipedia page linked to above.

Finally, the link to download this HP-41 program is here: newton-raphson.zip

It is provided in text listing format, a .raw file and a printable PDF with wand bar codes.

Here is a video of a HP-41CX finding various zeros of the function:

\[ f(x) = x^3-2x^2-11x+12 = (x+3)(x-1)(x-4) \]
The three zeroes are therefore $x=-3, x=1$ and $x=4$.

And here is the equivalent in BASIC for HP-71:

10 DESTROY ALL @ DELAY 0
20 REAL X,Y,Y1,E @ INTEGER P,M
30 P=FLAG(-17)+2*FLAG(-18)+4*FLAG(-19)+8*FLAG(-20) @ E=10^(-P) @ M=2*P+8
40 INPUT "GUESS? ";X
50 Y=FNF(X) @ IF ABS(Y)<E THEN 120
60 "X=" & STR$(X)
70 Y1=(FNF(E+X)-FNF(X))/E
80 IF Y1=0 THEN "CONSTANT?" @ END
90 X=X-Y/Y1
100 IF M>0 THEN M=M-1 @ GOTO 50
110 "NO CONVERGENCE" @ END
120 "ZERO: " & STR$(X) @ END
130 DEF FNF(X) = (X+3)*(X-1)*(X-4)

After running, the variable X contains the zero found and Y is the value of $f(x)$ calculated for that value of $x$ - this gives you the error, the absolute value of which should be lower than our $\epsilon $, which is stored in the variable E.

Numerical integration is an operation that many older machines are not able to perform without add-on libraries (e.g. Math Pac for HP-41C) or without writing a program from scratch to do it. There are, of course, some exceptions to this; Hewlett Packard's HP-15C and HP-42S come straight to mind, as does the Casio fx-180P, for example, but these machines are actually the exception, not the rule.

There are many methods used to calculate definite integrals, that is integrals between known boundaries yielding a numerical result. One method that is a good trade-off between precision and complexity of application is Simpson's Rule, which attempts to find a quadratic of the form $a\cdot x^2+b\cdot x+c$ that fits or is close to our function. Finding the integral of this polynomial is very easy:

\[ \int_{x_1}^{x_2} \! (a\cdot x^2 + b\cdot x + c) \, \partial x = \frac a 3 (x_2^3-x_1^3) + \frac b 2 (x_2^2-x_1^2) + c\cdot (x_2 - x_1) \]

So, what does this mean? If we sample the function at the lower and upper boundaries and once more in the middle, we can get an approximation of the integral of the function by just adding the y-coordinates of the sample points and applying a few coefficients. Easy.

As with any approximation method that involves sampling, we can make this even more accurate by increasing the number of samples if we divide the region that we want to integrate into multiple smaller regions that we sample individually. This is thanks to (assuming a<c<b):

\[ \int_a^b \! f(x) \, \partial x = \int_a^c \! f(x) \, \partial x + \int_c^b \! f(x) \, \partial x \]

I wrote something for a few vintage machines that shows this method in action. The video below shows a Sharp PC-1360 and a Casio PB-410F running programs written in BASIC, followed by a SwissMicros DM41L and a Hewlett Packard HP-41CX running a similar program in RPN keystroke. You can get the listing for HP-/DM41 along with a .raw file and printable bar codes for use with a bar code wand here: simpson.zip

In this example, I'm getting all four machines to calculate:
\[ \int_0^1 \! (x^4-3x^3+x^2+1) \, \partial x \]
The exact answer to this is $ \frac{47}{60} \approx 0.7833333 $

In all examples I'm using 4 as the number of steps/divisions to use, which actually equates to $2^4=16$, i.e. I broke the [0;1] interval down into 16 smaller intervals (hence the progress counting up in increments of $\frac 1 {16} $= 6.25%).

There are two scientific calculators recently produced that, I'm afraid, fall into the cheap, plasticky category. They are the HP300s+ and the HP10s+.

The question is, are they really Hewlett Packard machines at all?

They are not. They are in fact Casios that have been rebadged to look like HP machines.

Want proof? Watch this video with the HP10s+ showing its real colours. If you press the MODE key four times you get to the menu where you can alter display settings. There is an undocumented function in this menu where, if you press '2', you get to the contrast setting. This is not mentioned in the manual and, indeed, it has no effect, but look at what you get on screen when you press '2'.

One good thing about this little machine is that I didn't even have to put a battery in it. The solar panel above the screen provides enough power to run the calculator as long as there's enough light around.

Err, right. The HP Prime is hardly a vintage calculator given that it was first released in 2015. Better still, HP released the so-called Prime "G2" in August 2018 with faster hardware, much more RAM to work with and double the storage space in flash memory.

When that happened, there was no excuse, I had to get one. At the time of writing, the Prime G2 would appear to be available only in Europe. The Americas have been left by the wayside this time around. I bought mine from derekenwinkel.nl with whom I have no affiliation other than being a happy customer of theirs.

As it became known that there was an updated version of the Prime, people in the Museum of HP Calculators Forum were interested in hard data showing the improvements in performance, so I went and wrote a benchmark.

The benchmark in itself is probably of limited value in absolute terms but gives a good idea of the differences between different machines.

A benchmark run can comprise up to three different types of test.

Firstly, there's the "Savage" test, which gives an idea of the accuracy of the calculator.

You start off with the value '1' in a variable. Let's say 'x' for argument's sake. You then calculate repeatedly:

\[ x = tan(atan(e^{ln(\sqrt{x^2})})) + 1 \]

If the calculator was absolutely accurate, this would be exactly the same thing as: \( x = x + 1 \)

But it's not completely accurate. With each iteration, a small error is introduced, which gets compounded into the next iteration etc. At the end of the test, when all the iterations have been calculated, we calculate the difference between the final result obtained and the "perfect" result, then we divide this discrepancy by the perfect result, which gives us the relative error. We also time how long it takes the calculator to perform the test.

Secondly, there's a summation test, which is designed to find out how quickly the calculator can chew on a series of calculations involving transcendental functions. In this case, we calculate:

\[ \sum_{k=1}^n \sqrt[^3]{e^{sin(atan(k))}} \]

It's a function with no intrinsic value or meaning other than it gets the calculator to work on trigonometric and exponential functions.

Finally, there's an implementation of a solution to the "N Queens" problem. We time how long it takes for the Prime to find the first solution and all the solutions to this problem on an 8x8, 9x9 or 10x10 board.

The "Num" and "Num Setup" views are used in this app. The app starts on the "Num Setup" view, in which you tell the benchmark how many iterations of the first two tests you want to run and how large a board you want to use for the "N Queens" test. When you hit the [OK] soft button it goes straight to the "Num" view, where it performs the tests and gives you the results:

Additional views in the "View" menu are "Reset", which as its name suggests, resets the preferences you set up in the "Num Setup" view, and "Last results", which displays again the results of the last test run without going through with the test.

Two variables are exported by this app: bmOptions and bmResults. Both are lists of raw data. bmOptions contains the options you gave in the "Num Setup" view and "bmResults" contains the results of the tests.

Tests can be invoked from the Home screen or from another app by using the exported DoBenchmark() function and passing to it a list of the form:

{a, b, c}

...where a represents the number of iterations of the Savage test to perform, b that of the Summation test and c the size of the board for the "N Queens" test. These numbers are, for a and b:

1: Skip the test

2: 1000 iterations

3: 2000 iterations

4: 5000 iterations

5: 10000 iterations

6: 20000 iterations

7: 50000 iterations

8: 100000 iterations

You can supply numbers greater than 8 if you wish. They will follow the same progression as the numbers 2 to 8 above, so 9 means 200000, 10 means 500000 etc.

For c, the number is:

1: Skip the test

2: 8x8 board

3: 9x9 board

4: 10x10 board

You can use numbers greater than 4 for c if you wish. The general case is, the board will be a (c+6)x(c+6) board.

So, to run 20000 iterations of the Savage test, 10000 iterations of the Summation test and the "N Queens" problem on an 8x8 board from the Home screen:

DoBenchmark({6,5,2})

(Don't forget to qualify the function if you're calling it from a different app: Benchmark.DoBenchmark())

You should get a list back something like this:

{

{"Savage", {20000, 0.14, 1.2980065E-6}},

{"Summation", {10000, 0.078, 13955.8578444}},

{"Queens", {8, 0.009, 876, 0.156, 92, 15720}}

}

This is a list of lists. Each list in this list contains two elements. The first is a string representing the name of the test and the second is another list containing the results of the test.

The meanings of the values within the result list depend on the test itself.

For the Savage test, the results are firstly the number of iterations performed, secondly the time in seconds taken to run the test, and thirdly the relative error.

For the Summation test, the first two elements of the result list are as for the Savage test, and the third element is the sum of the terms calculated during the course of the test.

For the "N Queens" test, the results are the size of the board, the time in seconds taken to find the first solution, the number of combinations examined to find that first solution, the time in seconds taken to find all of the solutions, the number of solutions found and, finally, the number of combinations examined to find all of the solutions.

An individual test's result is {0} if the test is not performed, so:

DoBenchmark({1,1,2})

Should give you something like this in return:

{

{"Savage", {0}},

{"Summation": {0}},

{"Queens", {8, 0.009, 876, 0.156, 92, 15720}}

}

All three tests show that the G2 is approximately three times as fast as its predecessor. The test results below are firstly from my Rev. C hardware Prime and then from my G2 below it.

Now this is something unusual. Who would want to use a 30-year-old machine worth something as a mere egg timer, or use it at all in a kitchen, where it could easily get damaged?

It just so happens that one of the machines in my collection is a SwissMicros DM41. It's built really solid and it's basically the same thing as a Hewlett Packard HP-41CX in a case the size of a credit card, so that means that it incorporates, among other things, a Time Module, which gives it a stopwatch, countdown timer and alarm capabilities.

The DM41 is a great little piece of technology. However, the operative word here is "little". While its LCD is the same size as it's Voyager-sized big brother, the DM41L, its keys are just a bit too small for the device to be fully practical, but for some things its form factor makes it just right. Okay, it's more than an egg timer. This said, my DM41 gets used most of the time in the kitchen as a timer while I'm cooking. I keep it in the breast pocket of my shirt.

The program I'm showcasing here isn't restricted to the HP-41CX and DM41(L), it will also work on the HP-41C or HP-41CV as long as it's fitted with a Time Module (HP-82182A).

The idea behind this was to give me a quick way of having an alarm go off after a set amount of time. There are two ways of going about this on the '41. You can set the stopwatch to a negative time using SETSW and start it going with RUNSW. It will count upwards towards zero and when it gets there, it will emit a single beep and continue counting. The advantage of this option is that you can follow the progress of the countdown. Alternatively, you can calculate what the time will be after the set amount of time has elapsed and set an alarm for that time using XYZALM. With this option you won't know how long there is to go before the alarm goes off, but you will see an indication of the time for which it was set after running CDOWN.

The first option is easy enough as long as the required instructions have been assigned to keys in USER mode, but when the time has elapsed, it's easy to miss the single beep while you're going about your business. The second option gives you a full-blown alarm with all the flexibility that implies, but you need to calculate the alarm date as well as the time in case the countdown time takes you beyond midnight. This is exactly what the program CDOWN does.

CDOWN is easy to use:

Set the alpha register as you would if creating an alarm manually. So, that's with a message, blank, or with a global label (refer to the Time Module manual for details).

Enter the time to count down in the form HH.MMSS (e.g. 0.0530 for 5m30s)

Run CDOWN (either XEQ it or assign it to a USER key)

You'll see the time of day when the alarm is set to go off in X after CDOWN runs.

The archive contains a text listing of the program that's compatible with hp41uc and dm41.swissmicros.com, a .raw file and a printable PDF with wand bar codes.

The first post on this blog goes back to September 2009 and we are now about to go into 2019. So many things have changed since then.

The original idea behind this blog was to publish periodical tips and tricks mainly related to GNU/Linux and other POSIX operating systems on one hand, and Symbian mobile phones on the other. Guess what... I no longer use GNU/Linux as my main operating system because I'm no longer self-employed and the work that I now do means that using MS-Windows is my only real option. I still use Linux on a handful of Amazon Web Services EC2 machines and on virtual machines at home and at work, but my main workstations are Windows 10 machines.

So, what about mobile phones and Symbian? We all know what happened to that. Nokia discontinued Symbian and switched to Microsoft's Windows Mobile platform, and sold the mobile division to Microsoft, who promptly killed it off. A Chinese manufacturer took out a license to build and sell mobile phones under the Nokia brand and that is what's on sale now, although it has very little to do with the Nokia brand of yesteryear.

Not only that but, no longer being self-employed, I don't have the freedom to organise myself as I want, which has left me little time to post anything here for a number of years, although I'm hoping to be able to start posting again in the not too far future given that I will be far less involved in 41 Club in just over 3 months from now, when I step down from the Association's National Executive.

If you've seen my previous post on this blog from nearly 18 months ago (although I have kept it up to date since then!) then you'll know that I've revived a collection that I started when I was in my early '20s living in France, a collection of calculators. Not just any calculators, though. There is so much Chinese crap flooding the market, cheap "4-bangers" (calculators with the 4 basic operations) that cost pennies and flimsy, plasticky scientific machines that look like they'll break if you look at them wrong. I don't want any of that. What I want is well-built machines that feel solid and are programmable and I have a distinct preference for stuff that was popular in the '70s and '80s. I am also involved, on an entirely voluntary basis (I'm not a member of their staff and I don't get paid!), with a Zürich-based company called "SwissMicros", who build calculators that behave like some of the popular models made by Hewlett Packard in the '80s.

Edit: November 2020. I have been working part time for SwissMicros as an independent contractor since July this year.

So, that is how my interests have shifted over the past 10 years. You can now expect a few blog entries about vintage calculators :)