A CURTA model II mechanical calculator is simulated in its visible operations. In the drawings below you see the machine in a front view at the left and a top view at the top right. For ease of understanding a synoptic view of the registers is added at the bottom right.
Click the “Show Legends” button to show the names of the parts and the points where you can click to operate the machine (input register sliders have to be dragged).
Like most mechanical calculators the CURTA has an input register where the user selects the digits of a number, a result register where the result of arithmetic operations are shown, and a counter register that counts the number of times the crank has been turned.
At the start all registers show zero, the crank is in the adding position (down), the counter inversion switch is up (the counter counts counts positively) and the register clear handle (ring sticking out) is at the right.
To operate the calculator:
At the front, slide the red and black sliders up or down on the input register to set an input number.
Click the crank handle in either the top or front view to make it perform a single revolution, this will add the number of the input register to the result register, and will add one to the counter register. The crank only turns in clockwise sense.
Click the cap in the front view at the left or the right to make the cap turn by one position, or click one of the small position numbers to move the cap to that position (only positions 1 to 8 are possible). The cap lifts, turns and then drops again. This shifting is used for multiplication and division.
Click the crank in its axle on either view to make it go up or down. When it is up a red ring shows to warn you that the machine now subtracts the input number from the result (internally it actually still adds, but adds the ten's complement).
In the top view, click one side of the clearing handle to clear the register on the side you clicked. The handle will then go to rest at the other position between the result and the counter registers. You can clear both registers at once by clicking the clearing handle in the front view. There is no way to clear the input register except by sliding all sliders up to their zero position.
Click the counter inversion switch to set it to its down position (a red warning dot appears to the right of the counter register in the synoptic view). The counter now subtracts one at each revolution. This is used in division.
The Four Arithmetic Operations
In the four sections below, “Machine Ready” means: (1) clear all the registers, (2) put the cap in position 1 (to the very left) (3) put the crank in its down position and (4) the counter inversion switch in its up position.
We will add the numbers 123, 456 and 789.
Set 123 on the input register by sliding the slider 3 (red) to the position where 1 shows above it, slider 2 to position2 and slider 1 to position 3. The number 123 shows in the input register on the front vies and also the input register in the synoptic view.
Turn the crank once by clicking its handle in either the front or top view. The number 123 shows in the result register (it was added to the already present 000).
Set the input register sliders to show 456 in the input register.
Turn the crank once. 456 is added to the result register, showing 579.
Set the input register to 789.
Turn the crank, the result is 1368.
Note that the counter register shows 3 because the crank was turned 3 times, but this has no importance in simple additions.
We will subtract 432 from 987.
Set 987 on the input register.
Turn the crank once. The number 987 shows in the result register.
Set 432 on the input register.
Pull the crank up (to show its red ring) by clicking on its axle, it will now subtract.
Turn the crank once. 432 is subtracted from the result register, showing 555.
Note that the counter register shows 0 because the crank was turned 1 time in its down position and one time in its up position: 1-1=0, but again this has no importance in simple subtractions.
We will multiply 1234 by 32. Notice the similarity with the procedure you used at school.
Set 1234 on the input register.
Turn the crank twice. The number 1234 is added 2 times to the result register, showing 2468 and the counter shows 2.
Turn the cap one position to the right by clicking it on its right side (the cap lifts, turns and comes down again).
Turn the crank three times. The number 1234 is added three times but one position to the left, which you can interpret as 12340 being added 3 times or 1234 being added 30 times. The result is 39488 and the counter shows 32.
The counter now shows a significant number: 32, the multiplicator of 1234.
We will multiply 1234 by 98. Using the same method as above we would turn the crank 8 times and then 9 times or a total of 17 times. But we can do much better:
Set 1234 on the input register.
Lift the crank to show the red ring.
Turn the crank twice. The number 1234 is subtracted 2 times from the result register, showing 999999999997532 and the counter shows 99999998.
Turn the cap two positions to the right, 3 is above the cap position indicator.
Push the crank down again to hide the red ring and make it add again.
Turn the crank once. The number 123400 (cap position 3!). The result is 120932 and the counter shows 98.
We turned the crank only 3 times. The trick consists of subtracting instead of adding as soon as the digit to multiply by exceeds 6, then adding once at the next cap position.
We will divide 6543 by 37. Again notice the similarity with the procedure you used at school.
Set the cap as far to the right as possible, e.g. by clicking on the small number 8 at the bottom of the cap, or by clicking the cap's right side until this extreme position is reached. This puts result digit 15 above input register digit 8.
Set 6543 on the input register, but instead of using sliders 4 through 1, use sliders 8 through 5.
Turn the crank once. The result register shows 654300000000000.
Clear the counter register by clicking the ring in the top view on the side of the white counter register. The result remains, the counter is 0.
Set 37 on the input register at sliders 8 and 7, put sliders 6 and 5 back to 0.
Click the counter inversion switch, it will slide down.
Pull the crank up to show its red ring. Turning the crank will now subtract, but the counter will count up because of the position of its switch.
Turn the crank once. That subtracts the 37 from the 65 (first two digits) and leaves 284300000000000 in the result, 1 in the counter. We can't subtract another 37.
Turn the cap one position to the left, this puts the input 37 now under the 84 of 284300000000000.
Turn the crank until you can no longer subtract 37, i.e the two-digit number in the result register just above the 37 becomes smaller than 37. If you go one turn too far then a 9 will appear to the left; in that case recover by pushing the crank down, turning once and lifting it again. You should now have 025300000000000 in the result and 17000000 in the counter.
Turn the cap another position to the left and repeat the previous point. Do this until the cap reaches its end position. You should now have 000000029000000 in the result and 17683783 on the counter.
The result is of course not 17683783 but 176.83783. The problem is to know where the decimal point is. The real machine has some separator indicators and there are procedures to place them so that one of them indicates the decimal point. However, those are a finer points and not the object of the simulator at this time (2019-04).
About the Simulator
A CURTA model II is used for this simulator: it has 11 input digits, 15 result digits, 8 counter digits and 8 shift positions.
No images are used: all you see is made with vector graphics.
The simulator only shows how to operate the machine. It does not show how the carry mechanism is implemented, how the clearing of registers works internally, how the ten's complement is computed. I.e. the simulator lets you operate the machine but it does not tell you how it actually works.
Parts shown are:
a flattened input register with the cursors for the 11 input digits and the counter inversion switch
a top view of the cap with the crank, the result and counter registers and the clearing handle,
the three registers in linear form.
There is no attempt at 3D visuals even though SVG allows some. The front view is “flattened” on purpose because the number of input digits on the model II is too high for them all to be visible at once from the front. The impact of this flattening on operation is unimportant. The most significant deviations from a real view are:
all sliders of the input digits are visible at once and the space between them is less than half the real distance,
the counter inversion switch has been moved very close to the right of the first input slider whereas in reality it would be out of sight on the other side of the machine.
Though the resulting image looks “flat” it still has the same silhouette as the real machine. Using very dark colours, turning the crank in front view did not give any impression of it passing in front first and then in the back before returning to its resting position. Therefore I opted for a much lighter colour for the thin vertical side of the crank and the handle bearing under the crank.
The top view displays the machine as accurately as I could make it.
The commas/thousands separators are not shown. On the real machine there are three in the bottom groove and six in the top cover groove. Their presence is not necessary for understanding how to operate the machine. I may add them later.
When the crank is turned slowly on the real machine, it is obvious that the carry mechanism is not simple at all. I don't quite understand it…
the cursors of the input register can be dragged to desired positions, and the inversor switch clicked to change its position,
the crank handle can be clicked to turn one full turn,
the crank axle can be clicked to change between the pulled-up to the pushed-down position,
the cap can be shifted left or right one position at a time, or to a desired position,
the clearing handle can be clicked to clear either of the result or counter registers or both.
Thus, for the cap:
the crank always rests in the same position and does not rotate with the cap,
the clearing handle rotates with the cap,
the clearing handle always rests in one of the positions between the result and counter registers.
How the simulator was made
To work with whole numbers, the dimensions of the actual machine are expressed in tenths of a mm, thus what in reality would be 3.4mm would here be expressed as 34. Angles are in degrees and to avoid dealing with negative angles they may be greater than 360.
Objects are generated around 0,0 as their object centre, then transformed as needed.
There are 15+8+11 = 34 digit wheels. Each digit wheel on the cap is represented as a black background rectangle with a white digit. Since the digits need to change, each digit is a clone of one of ten digit glyphs.
The digit glyphs were designed by hand in SVG, trying to match the real digit font as close as possible. Their form may still be tweaked in the future. Because of pixel-size differences some digits may not look perfect in all postions in all registers. However, there are really only 10 separate designs.
Dimensions and Coordinate Systems
Top circle: (in 0.1mm)
inner diameter: 510
digit width: 25, inter-digit space: 42, inter register space: 72
angle between digits: 15º
15x(14+7)=315, leaves 360-315=45, or 22.5º on each side between the registers.
In the figure at the right, let 0º pass through the centre of the result register's first digit. Let angles increase clockwise (they do so in SVG anyway). Then:
Input register digits are at 0, 15, 30, …, 150 degrees,
Result register digits are at 0, 15, 30, …, 210 degrees,
Counter register digits are at 210+22.5=232.5, 247.5, …, 337.5 degrees.
A “CH” indicates the resting positions of the Clearing Handle.
This helps in deciding when to set a digit to 0 as the reset handle passes over it.
In the real machine there is something sophisticated going on: when the clearing handle turns clockwise, digits are cleared slightly ahead of the handle, if it turns counterclockwise they are cleard slightly after the handle passes over them. But this happens only at the start of the clearing operation, towards the end (before the handle reaches its resting position) digits closer to the handle and finally under the handle are cleared. This is very difficult to simulate, I decided to clear a digit only under the handle so that we don't even have to simulate the rotation of the digit wheels.
The handle has two resting positions: one in each of the centres of the register separation spaces (which themselves are -22.5/2 = -11.25º away from a digit's centre). These positions are at 337.5º (resting position 1) and 232.5º (resting position 2). However:
When clearing the counter starting from position 1, we rotate counterclockwise, the angle decrements from 337.5 to 232.5 and remains positive throughout.
When clearing the counter starting from position 2, we rotate clockwise, the angle increments from 232.5 to 337.5 and remains positive throughout.
When clearing the result starting from position 1, we rotate clockwise, the angle increments from 337.5 and goes over 360. We can then either subtract 360, i.e. start from -11.25 and go to 232.5, or we can add 360, i.e. go to 232.5+360.
When clearing the result starting from position 2, we rotate counterclockwise, the angle decrements from 232.5 and should stop at -11.25 but is being compared to 337.5. We can again subtract 360 in one sense or add 360 in the other.
The problem with clearing the result could also be solved by using two different values for resting position 1: 337.5 for the counter and -11.5 for the result. This solution is effectively used by comparing with cRegisterDivide1-360 in the result procedures.
To make it easier to decide when to clear a digit as the clearing handle passes over it, we move the clearing handle in increments of 5º, but because it starts at either -11.25º or 221.25º we begin by putting it at a whole multiple of 5º: -10 or 220º . Then, as its angle modulo 15 is zero, we clear the digit corresponding to its position.
Both resting positions are taken to be at positive angles. After clearing the handle has to be in the other resting position. This makes a more general mechanism so difficult that it is easier to use four unfortunately very similar routines rather than trying to fold them up into one.
All graphics are fairly simple SVG objects. There are no images, only vector graphics.
Trick for those who want to play with the code: option-clicking (alt key) on the Show Legends button displays a grid of 100x100 units and a circle around the path of the clear handle. This aids in positioning elements.
Using stroke-dashoffset to simulate rotating the cap in front view works well but is of course a trick. It avoids having to clip.
All graphic objects that are referred to by id have their handle stored during the setup phase, so there should not be uses of document.getElementById after setup. During setup (i.e. inside the Setup() function) there are a few local references, used only to position graphic elements.
A few numbers remain in the code: they are small offsets to make things look slightly prettier and it was deemed not worth the trouble to define them as parameters: they would have needed very long names and are used only once and only during setup. An example is the distance from the top cover of the CURTA name. These numbers are marked in the code with the word tweak.
To handle the illusion that in the front view the crank passes in front of the axle there is a small section of a slightly lighter colour which is painted “in front” or “behind”. Its shape is calculated at each angle, but is geometrically different in certain sectors of the total crank revolution. Since the crank angle increases uniformly, it is easy to know in which sector we are by looking at which crucial angles have already been passed. This is quicker and simpler to program than testing against a set of upper and lower limits.
Handle animation requests by queueing them and finishing one before starting the next.
Animation procedures all use setTimeout to call themselves until a condition is met.
To recognise them easily their names start with “Do”. They are:
None of them uses parameters (those are set up in global variables beforehand). They cannot be called directly, the procedures that need them must push a request onto the queue.
We assume that moving the cursors of the input register and switching the counter do not use any time (i.e. will always be terminated before the user has time to start another interaction).
The animation requests are pushed onto an array gAnimation. The function Animate checks the queue at reasonable intervals (say every 100ms) to see if anything is on it, locks a semaphore (gDone) and waits until that is unlocked by the animating procedure before starting the next animation on the queue.
The real machine has mechanical interlocks: a new operation can only start when the previous one is finished. E.g. it is not possible to lift the cap while the crank is not in its rest position. Queueing the requests simulates this well enough.
At first the digits were taken from Helvetica, no font was found to be closer to the Curta's digits. A possible solution would be to use a path for each digit instead of a font glyph, and this was ultimately adopted. There is no noticeable increase of processing time.
An attempt was made to use SVG filters to show some 3D and lighting effects. These do introduce a noticeable delay when clearing registers because the clearing handle has to be redrawn with a different lighting at each position, and furthermore the two little buttons have to be separate with a separate filter. Finally, the filters turn with the objects, it is impossible to fix them to a different frame, they do not work in Firefox and there is no way to modify their attributes satisfactorily. In the end I abandoned them infavour of simple flat fills. It does not look too bad.
The real machine in front (side) view is a cylinder. On the model II not all input digits are then visible and also the counter inversion switch is most of the time out of view. At first I rolled the cylinder out flat, but then the cap's 15 digit positions become very wide and the counter switch is far away to the right. To cope with that I took a few liberties: move the sliders closer together, only show 11 positions of the cap at a time and put the counter switch adjacent to the first input slider.
Making the interslot step 1.8mm instead of 4.8mm makes the flat front image look much better and the sliders then all fit into a space that corresponds to the width of the actual machine when seen from the front. I decided to leave it flat, despite the relative ease of introducing a round look to some parts.
Making the cap and bottom grips “rounded” looks worse because of lack of perspective up-down.
On my machine the crank is the only element made from plastic. There is a triangle on top of its axle centre, it points to the counter digit that is currently incremented or decremented. The paint of this arrow is yellowish, probably because of age (I bought my Curta in 1969). I used plain white in the SVG.
Most of the machine is black. To distinguish parts better, levels of grey are used as fill colours:
#000 for stroke, fill background of digits (wheels)
#222 for the cap, bottom
#333 for surfaces that are inclined (usually 45º or close to that)
#444 for surfaces that are horizontal (mainly for the top view) or are the bottom of the grooves
Symmetric paths have their origin in the centre. Rectangles have their origin at top left; Digits (unfortunately?) have their origin at bottom left instead of centre.
The Real Machine
The real machine can only add.
When the cap is in position 1, there are four result digits to the left of the leftmost input digit. Those digits must also increment in case there are carries, and therefore inside the machine there are vertical axles for that purpose. They are identical to the axles for the input digits but their engaging sprockets are fixed at position zero (at the top).
These outlines show the SVG design elements. The small red circles show the outline's origin (coordinate 0,0 for its path).