Skip to content

Instantly share code, notes, and snippets.

@sinclairtarget
Created August 17, 2018 20:22
Show Gist options
  • Star 114 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save sinclairtarget/ad18ac65d277e453da5f479d6ccfc20e to your computer and use it in GitHub Desktop.
Save sinclairtarget/ad18ac65d277e453da5f479d6ccfc20e to your computer and use it in GitHub Desktop.
Lovelace's Note G Program in C
#include <stdio.h>
/*
* Calculates what Ada Lovelace labeled "B7", which today we would call the 8th
* Bernoulli number.
*/
int main(int argc, char* argv[])
{
// ------------------------------------------------------------------------
// Data
// ------------------------------------------------------------------------
float v1 = 1; // 1
float v2 = 2; // 2
float v3 = 4; // n
// ------------------------------------------------------------------------
// Working Variables
// ------------------------------------------------------------------------
float v4 = 0;
float v5 = 0;
float v6 = 0; // Factors in the numerator
float v7 = 0; // Factors in the denominator
float v8 = 0;
float v10 = 0; // Terms remaining count, basically
float v11 = 0; // Accumulates v6 / v7
float v12 = 0; // Stores most recent calculated term
float v13 = 0; // Accumulates the whole result
// ------------------------------------------------------------------------
// Result Variables
// ------------------------------------------------------------------------
float v21 = 1.0f / 6.0f; // B1
float v22 = -1.0f / 30.0f; // B3
float v23 = 1.0f / 42.0f; // B5
float v24 = 0; // B7, not yet calculated
// ------------------------------------------------------------------------
// Calculation
// ------------------------------------------------------------------------
// ------- A0 -------
/* 01 */ v4 = v5 = v6 = v2 * v3; // 2n
/* 02 */ v4 = v4 - v1; // 2n - 1
/* 03 */ v5 = v5 + v1; // 2n + 1
// In Lovelace's diagram, the below appears as v5 / v4, which is incorrect.
/* 04 */ v11 = v4 / v5; // (2n - 1) / (2n + 1)
/* 05 */ v11 = v11 / v2; // (1 / 2) * ((2n - 1) / (2n + 1))
/* 06 */ v13 = v13 - v11; // -(1 / 2) * ((2n - 1) / (2n + 1))
/* 07 */ v10 = v3 - v1; // (n - 1), set counter?
// A0 = -(1 / 2) * ((2n - 1) / (2n + 1))
// ------- B1A1 -------
/* 08 */ v7 = v2 + v7; // 2 + 0, basically a MOV instruction
/* 09 */ v11 = v6 / v7; // 2n / 2
/* 10 */ v12 = v21 * v11; // B1 * (2n / 2)
// A1 = (2n / 2)
// B1A1 = B1 * (2n / 2)
// ------- A0 + B1A1 -------
/* 11 */ v13 = v12 + v13; // A0 + B1A1
/* 12 */ v10 = v10 - v1; // (n - 2)
// On the first loop this calculates B3A3 and adds it on to v13.
// On the second loop this calculates B5A5 and adds it on.
while (v10 > 0)
{
// ------- B3A3, B5A5 -------
while (v6 > 2 * v3 - (2 * (v3 - v10) - 2))
{ // First Loop:
/* 13 */ v6 = v6 - v1; // 2n - 1
/* 14 */ v7 = v1 + v7; // 2 + 1
/* 15 */ v8 = v6 / v7; // (2n - 1) / 3
/* 16 */ v11 = v8 * v11; // (2n / 2) * ((2n - 1) / 3)
// Second Loop:
// 17 v6 = v6 - v1; 2n - 2
// 18 v7 = v1 + v7; 3 + 1
// 19 v8 = v6 / v7; (2n - 2) / 4
// 20 v11 = v8 * v11; (2n / 2) * ((2n - 1) / 3) * ((2n - 2) / 4)
}
// A better way to do this might be to use an array for all of the
// "Working Variables" and then index into it based on some calculated
// index. Lovelace might have intended v14-v20 to be used on the
// second iteration of this loop.
//
// Lovelace's program only has the version of the below line using v22
// in the multiplication.
if (v10 == 2)
{
/* 21 */ v12 = v22 * v11; // B3 * A3
}
else
{
/* 21 */ v12 = v23 * v11; // B5 * A5
}
// B3A3 = B3 * (2n / 2) * ((2n - 1) / 3) * ((2n - 2) / 4)
// ------- A0 + B1A1 + B3A3, A0 + B1A1 + B3A3 + B5A5 -------
/* 22 */ v13 = v12 + v13; // A0 + B1A1 + B3A3 (+ B5A5)
/* 23 */ v10 = v10 - v1; // (n - 3), (n - 4)
}
/* 24 */ v24 = v13 + v24; // Store the final result in v24
/* 25 */ v3 = v1 + v3; // Move on to the next Bernoulli number!
// This outputs a positive number, but really the answer should be
// negative. There is some hand-waving in Lovelace's notes about the
// Analytical Engine sorting out the proper sign.
printf("A0 + B1A1 + B3A3 + B5A5: %.2f\n", v24);
}
@Dithermaster
Copy link

This was one of the reasons that Knuth developed TeX. Your options were bodge the notation on your typewriter or pay someone who knew typesetting but not your math to make it look good.

It is also the reason why Babbage created a printer for the Difference Engine, since some of the errors in the books of tables were due to typesetting errors. It took the result of the last register and embossed them into plaster, which could be use to mold metal type.

@switham
Copy link

switham commented Jul 11, 2020

Ada's diagram (see neopaf's note) reminds me of Fortran coding forms, or the general forms they used for preparing things to be punched into cards. Both came in tear-off pads. Also the way I would write assembler code (label, op-mnemonic, two arguments, comment) in my notebooks leaving columns for hand-assembly into machine language (address, three bytes, running total of clock cycles!). Ada's diagram as typeset looks so modern and familiar and was the only thing of its kind published for decades.

@switham
Copy link

switham commented Jul 11, 2020

I wonder whether there were people at the time who got through Ada's gigantic screed finally to that page and got it. "OMG those are the exact steps and what would be in each register and you would punch it into cards and it would just do it!!" ... or maybe nobody had that reaction.

@ziroby
Copy link

ziroby commented Jul 24, 2020

... or maybe nobody had that reaction.

I bet Alan Turing had that reaction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment