Charles Babbage wrote 1837: "What is the smallest positive integer whose square ends in the digits 269,696?" A solution within the features of the Analytical Engine (AE) would be appropriate, so there is no string processing and no floating-point numbers, no built-in square-root, and the remainder of a division used to determine the trailing digits. The (integral or fixed-point) numbers were rather long, 30 decimal digits. We assume the execution time for an addition to be 1 second, and for a division as well as a multiplication 1 second per digit (excluding leading zeroes). Just to show the order of time, 10 seconds will be assumed for each multiplication and division. (Maybe the division by a power of ten was much quicker.) The simple but reliable method to probe all intergers (manually entered start point, e.g. 500 for the above example), about 20000 multiplications and the same number of divisions were needed, running about 400,000 seconds, or 111 hours or nearly 5 days. Babbage surely would have never considered to use his precious machine this way. Instead of enumerating the squares by multiplication, the binominal formula x² = (x-1)² + 2x - 1 could be used to enumerate the squares. Now we have 3 seconds to provide the next square, 10 seconds for the remainder, and 1 second to test the result, i.e. 14*20,000 seconds or 78 hours or 3 days, still too long. (In modern computers, where the multiplication is not slower than an addition, this version will even be longer, as more instructions are performed). It is well known that any square number can only end in the digits 0, 1, 4, 5, 6 and 9; so the problem is solvable, as it ends in 6. To produce the end digit 6, only numbers with the end digits 4 and 6 need to be considered. Thus, when enumerating squares, we can step by alternatingly by 2 (_4 to _6) and 8 (_6 to _4), which reduces the time to 4000 rounds with 14 seconds each, i.e. 56,000 seconds or 16 hours. The same for the last two digits _96 gives _14, _64, _36 and _96 nees 800 rounds, 11,200 seconds or 3 hours. Still Babbage as a mathematicion would not use such a raw attempt; but instead try to calculate the set of permissible set of endings: The inital set for 10 as a modulus and 6 as ending digit is {4, 6}. Now the sequences 04, 14, 24, ... and 06, 16, 26, ... squared and probed for the ending '96', giving the set {14 36 64 86}. The next step adds multiplies of 100 to the numbers of the set, and checks the squares for the ending '696', giving the set {264 236 736 764}. Two more sets, {264 2236 2764 4736 5264 7236 7764 9736} and {264 24736 25264 49736 50264 74736 75264 99736} are determined, where the last one contains two solutions, 25264 and 99736. As the sets have together 26 elements, for each 10 probes have to be done, i.e. 260 divisions. But as various other operations are required, we should estimate 20 seconds for each test, thus 5200 seconds or nearly 2 hours. An experienced human computer at that time can compare the trailing digits very quickly, so the "division" needs just one second. Moreover, the squares of 4, 14, 24, ... are not obtained by multiplication, but the binominal formula: (x + 10)² = x² + 2*10*x + 100 As only the result modulo 100 is required, only twice the last digit has to be added to the first digit, modulo 100. The addend is 8 for a trailing 4, and 2 for a trailing 6. For the number above, the pattern is in the first digits is recurring, i.e. 1, 9, 7, 5, 3 for the first digit, if 4 is the last digit, and 1, 3, 5, 7, 9 if 6 is the last digit. So it is only left to count the distance, to obtain two new set elements, and if the first square has the wrong ending (i.e. 36² = 296) and an even first digit, the whole series can be skipped. So one test would require not more than 5 seconds, giving 1300 seconds or about 20 minutes or less than half an hour, which I can confirm. (The setup not counted, as that has to be done to program a coumputer anyhow. And the situation for other numbers may not be equally advantageous.) Note that for the number 971041, the set method needs about the same time, but as the result is 126929 and most numbers have more digits, the machine would require 20*100,000 seconds or nearly 600 hours or 23 days. The major advantage of the set method is that is terminates if there is no result, while the others will run for ever. There is an infinite number of solutions. If 'x' is a solution (m is the smallest power of 10 with m \( Charles Babbage wrote 1837: "What is the smallest positive integer whose square ends in the digits 269,696?" A solution within the features of the Analytical Engine (AE) would be appropriate, so there is no string processing and no floating-point numbers, no built-in square-root, and the remainder of a division used to determine the trailing digits. The (integral or fixed-point) numbers were rather long, 30 decimal digits. We assume the execution time for an addition to be 1 second, and for a division as well as a multiplication 1 second per digit (excluding leading zeroes). Just to show the order of time, 10 seconds will be assumed for each multiplication and division. (Maybe the division by a power of ten was much quicker.) The simple but reliable method to probe all intergers (manually entered start point, e.g. 500 for the above example), about 20000 multiplications and the same number of divisions were needed, running about 400,000 seconds, or 111 hours or nearly 5 days. Babbage surely would have never considered to use his precious machine this way. Instead of enumerating the squares by multiplication, the binominal formula x² = (x-1)² + 2x - 1 could be used to enumerate the squares. Now we have 3 seconds to provide the next square, 10 seconds for the remainder, and 1 second to test the result, i.e. 14*20,000 seconds or 78 hours or 3 days, still too long. (In modern computers, where the multiplication is not slower than an addition, this version will even be longer, as more instructions are performed). It is well known that any square number can only end in the digits 0, 1, 4, 5, 6 and 9; so the problem is solvable, as it ends in 6. To produce the end digit 6, only numbers with the end digits 4 and 6 need to be considered. Thus, when enumerating squares, we can step by alternatingly by 2 (_4 to _6) and 8 (_6 to _4), which reduces the time to 4000 rounds with 14 seconds each, i.e. 56,000 seconds or 16 hours. The same for the last two digits _96 gives _14, _64, _36 and _96 nees 800 rounds, 11,200 seconds or 3 hours. Still Babbage as a mathematicion would not use such a raw attempt; but instead try to calculate the set of permissible set of endings: The inital set for 10 as a modulus and 6 as ending digit is {4, 6}. Now the sequences 04, 14, 24, ... and 06, 16, 26, ... squared and probed for the ending '96', giving the set {14 36 64 86}. The next step adds multiplies of 100 to the numbers of the set, and checks the squares for the ending '696', giving the set {264 236 736 764}. Two more sets, {264 2236 2764 4736 5264 7236 7764 9736} and {264 24736 25264 49736 50264 74736 75264 99736} are determined, where the last one contains two solutions, 25264 and 99736. As the sets have together 26 elements, for each 10 probes have to be done, i.e. 260 divisions. But as various other operations are required, we should estimate 20 seconds for each test, thus 5200 seconds or nearly 2 hours. An experienced human computer at that time can compare the trailing digits very quickly, so the "division" needs just one second. Moreover, the squares of 4, 14, 24, ... are not obtained by multiplication, but the binominal formula: (x + 10)² = x² + 2*10*x + 100 As only the result modulo 100 is required, only twice the last digit has to be added to the first digit, modulo 100. The addend is 8 for a trailing 4, and 2 for a trailing 6. For the number above, the pattern is in the first digits is recurring, i.e. 1, 9, 7, 5, 3 for the first digit, if 4 is the last digit, and 1, 3, 5, 7, 9 if 6 is the last digit. So it is only left to count the distance, to obtain two new set elements, and if the first square has the wrong ending (i.e. 36² = 296) and an even first digit, the whole series can be skipped. So one test would require not more than 5 seconds, giving 1300 seconds or about 20 minutes or less than half an hour, which I can confirm. (The setup not counted, as that has to be done to program a coumputer anyhow. And the situation for other numbers may not be equally advantageous.) Note that for the number '971041', the set method needs about the same time, but as the result is 126929 and most numbers have more digits, the machine would require 20*100,000 seconds or nearly 600 hours or 23 days. The major advantage of the set method is that is terminates if there is no result, while the others will run for ever. There is an infinite number of solutions. If 'x' is a solution (m is the smallest power of 10 with m \ calculate sets of endings increasingly t =: system cpu seconds xx =: use sets of endings e mod m ? showtimes tt =: ((system cpu seconds) - t) * 1000.0 tt =: format '%9.1f;' tt ? xx = () print "No solution" :> tail =: tt _ " (set method)" ?# x =: map xx give keys ascending x2 =: x * x print x __ (split x2 at ed.count) __ tail tail =: '' ?> \ print only the first one \ Simple, yet efficient only on modern machines: count and square t =: system cpu seconds x =: count and square find e mod m ? showtimes t =: ((system cpu seconds) - t) * 1000.0 tt =: format '%9.1f;' t x2 =: x * x \ steps =: x - math int sqrt e print x __ (split x2 at ed.count) __ tt _ " (count and square)" \ Enumerate squares t =: system cpu seconds x =: enumerate squares upto e mod m ? showtimes tt =: ((system cpu seconds) - t) * 1000.0 tt =: format '%9.1f;' tt x2 =: x * x print x __ (split x2 at ed.count) __ tt _ " (enum squares linearily)" \ Enumerate only squares ending in 4 or 6 t =: system cpu seconds x =: enumerate squares sparse upto e mod m ? showtimes tt =: ((system cpu seconds) - t) * 1000.0 tt =: format '%9.1f;' tt x2 =: x * x print x __ (split x2 at ed.count) __ tt _ " (enum multiples of 4 and 6)" split (x) at (l): r =: '' _ x \ convert to string h =: string r upto r.count - l t =: string r from -l :> h _ '_' _ t \ Simple method: Count and square \ ================================================ count and square find (ed) mod (m): x =: integer ed sqrt ?* (x*x) %% m ~= ed x =+ 1 :> x \ Still simple: Enumerate squares \ ================================================ \( Enumerate squares starting below the square root of a limit, until the limit is reached, using the binomial formula x² = (x-1)² + 2x - 1 \) enumerate squares upto (ed) mod (m): x =: integer ed sqrt y =: x * x ?* y %% m ~= ed x =+ 1 y =+ 2*x - 1 :> x \ Enumerate sparse \ ======================================= \( Enumerate squares starting below the square root of a limit, until the limit is reached. Depending on the end digit, the end digits are 0 0 1 1,9 4 2,8 5 5 6 4,6 9 3,7 Stepping is in increments of 10 using the binomial formula x² = (x-10)² + 20x - 100 \) enumerate squares sparse upto (ed) mod (m): x =: integer ed sqrt x =: 10 * (x // 10) \ must be multiple of 10 ld =: ed %% 10 \ last digit xa =: 0 xb =: 0 ? ld = 0 xa =: x ? ld = 1 xa =: x + 1 xb =: x + 9 ? ld = 4 xa =: x + 2 xb =: x + 8 ? ld = 5 xa =: x + 5 ? ld = 6 xa =: x + 4 xb =: x + 6 ? ld = 9 xa =: x + 3 xb =: x + 7 ! xa ~= 0 ya =: xa * xa yb =: xb * xb ?* ? ya %% m = ed :> xa xa =+ 10 ya =+ 20*xa - 100 ? xb = 0 ?^ ? yb %% m = ed :> xb xb =+ 10 yb =+ 20*xb - 100 \ Advanced: determine sets of endings \ ================================== \ from the old set, the new set is calculated \ by squaring each number in the old set, plus a multiple of inc \ next set from (old) step (inc) find (ed) mod (m): m =: 10*inc \ truncate e =: ed %% m \ this ending new =: {} ?# x =: give keys old \ multiplication used; linear advance is too complex here ?# y =: from x upto (x+m-1) step inc z =: y * y z =: z %% m \- print ?x __ ?i __ ?y __ ?z __ ?e __ ?m ? z = e new{y} =: y :> new show set (x): \ print x.count _ ':' nonl ?# i =: map x give keys ascending print i _ ' ' nonl print '' \ returns set of result use sets of endings (e) mod (m): res =: {} set =: {} set{0} =: 0 \ i =: 1 ?* i < m set =: next set from set step i find e mod m ? debug is enabled show set set ? set.count = 0 :> () \ no solution i =* 10 \ check if result is in final set ?# y =: give keys set z =: y * y z =: z %% m ? e = z res{y} =: y :> res \ enumerate powers of 10 powers of (base) upto (lim): ? $ = () $ =: 1 | $ =* base ? $ > lim $ =: () :> $ \ Helper Functions \ ================ \ Determine smallest power of ten larger than given number \ As to round up the decimal logarithm is limited in precision, \ use simple loop, which may even be quicker for small numbers. xpower of ten above (x): p =: 1 ?* p <= x p =* 10 :> p \+ stdlib