Post Reply 
[VA] Short & Sweet Math Challenges #23: "May the 4th Be With You !" Special
05-10-2018, 09:55 PM
Post: #9
[VA] Short & Sweet Math Challenges #23 - My Solutions & Comments
      
Hi, all:

Time to wrap up this S&SMC#23. Sadly, it seems it failed to grasp the attention of forum members judging by the scarcity of solutions/comments posted. I naively thought that there would be a considerable number of HP-71B and Star Wars fans here that would welcome this homage to the unofficial Star Wars' Day, May the 4th, but only J-F Garnier took notice and contributed his always valuable and interesting solutions and comments.

Also, although the very last Step (Step the Sixth) can be solved with every HP calc model out there from the HP-10C upwards (at least for 4-5 digits if not all 10-12), no one posted anything on it, not even J-F, a real pity. Anyway, these are my original solutions plus assorted comments:

Step the First:

"Write a program which accepts from the user an integer N from 1 to 19 and outputs the Nth digit of Log(10), the natural logarithm of 10 (= 2.302585092994045684 to 19-digit accuracy)."

My original solution is this 1-line program (48 bytes):

      1 DISP (PEEK$("0CFCD",4)&"4"&PEEK$("0D19A",14))[20-VAL(DISP$)][1,1]

Let's see:

      > 1 [RUN]       2
      > 2 [RUN]       3
      >18 [RUN]       8
      >19 [RUN]       4

The HP-71B 64 Kb ROM which holds the entire operating system and BASIC language includes a number of explicit mathematical constants to a high precision and we can make use of that fact to obtain the pre-stored constants without the need to compute them anew, thus saving lots of time. It's just a question of knowing their address within the ROM.

My solution uses PEEK to assemble the 19-digit value of Log(10) from the ROM, in reverse order, and then uses the string-slicing operator applied twice in succession not to a string variable but directly to the resulting string expression to obtain the digits from the one specified by the user to the end of the string, and once more to isolated the precise digit. The digit position specified by the user isn't stored in a variable (via INPUT, for instance) but taken directly from the display via DISP$. This fulfills the no-variables requirement.

Lessons learnt:

      - the use of PEEK$ to extract mathematical constants from the HP-71B System ROM.
      - the use of DISP$ to obtain a value from the user without storing it in a variable
      - the use of the string-slicing operator [] applied directly to a string expression
      - the fact that the [] operator can be applied more than once in succession

Step the Second:

"Write a program which accepts from the user an integer N from 1 to 32 and outputs the Nth digit of Pi/2 (= 1.5707963267948966192313216916397 to 32-digit accuracy)."

My original solution is this 3-line program (152 bytes):

      1 DESTROY ALL @ X=33-VAL(DISP$) @ A$=PEEK$("0DB0F",16)&PEEK$("0DA91",15) @ C=-1
      2 FOR I=1 TO 31 @ N=VAL(A$[I,I]) @ N$=STR$(N+N) @ IF LEN(N$)=1 THEN N$="0"&N$
      3 A$[I,I]=STR$(VAL(N$[2])+C) @ C=VAL(N$[1,1]) @ NEXT I @ DISP (A$&STR$(C))[X,X]

Let's see:

      > 1 [RUN]       1
      > 2 [RUN]       5
      >31 [RUN]       9
      >32 [RUN]       7


On the surface this seems exactly like the previous Step, only with another constant instead of Log(10). The difference is that while the 19-digit value of Log(10) does appear in the ROM, the 32-digit value of Pi/2 does not.

However, the value of Pi/4 does so it's simply a matter of retrieving it from the ROM and multiply it times 2 within the requirements, in particular not using standard math functions and no arithmetical operator except + or -, which my solution does digit-by-digit. Once assembled, the required digit at the location specified by the user is retrieved and output.

Lessons learnt:

      - some constants not in the ROM can be easily derived from the ones available there

Step the Third:

"Solve right from the command line the following equation:      Sqrt(x+1) + Sqrt(x+2) + Sqrt(x+3) + ... + Sqrt(x+98) + Sqrt(x+99) + Sqrt(x+100) = 700"

My original solution is this 2-line command-line expression (117 characters in all):

      >DESTROY ALL @ DIM T$[1400] @ FOR I=1 TO 100 @ T$=T$&"+SQR(FVAR+"&STR$(I)&")" @ NEXT I
      >VAL("FNROOT(0,0,"&T$[2]&"-700)")

            3.28838856035
(correct 12-digit value: 3.28838856020)

The first command line dimensions a string to hold the full equation, which is then assembled into it in a simple loop, and then the second line simply completes the following expression which uses the FNROOT root from the Math ROM to solve the equation with identical initial guesses, 0 and 0. Finally, the entire expression is evaluated using VAL, immediately obtaining the root, 3.28838856035.

The assembled expression which VAL evaluates is this 1307-character string:

FNROOT(0,0,SQR(FVAR+1)+SQR(FVAR+2)+SQR(FVAR+3)+SQR(FVAR+4)+SQR(FVAR+5)+SQR(F
VAR+6)+SQR(FVAR+7)+SQR(FVAR+8)+SQR(FVAR+9)+SQR(FVAR+10)+SQR(FVAR+11)+SQR(FVAR
+12)+SQR(FVAR+13)+SQR(FVAR+14)+SQR(FVAR+15)+SQR(FVAR+16)+SQR(FVAR+17)+SQR(FVA
R+18)+SQR(FVAR+19)+SQR(FVAR+20)+SQR(FVAR+21)+SQR(FVAR+22)+SQR(FVAR+23)+SQR(FV
AR+24)+SQR(FVAR+25)+SQR(FVAR+26)+SQR(FVAR+27)+SQR(FVAR+28)+SQR(FVAR+29)+SQR(F
VAR+30)+SQR(FVAR+31)+SQR(FVAR+32)+SQR(FVAR+33)+SQR(FVAR+34)+SQR(FVAR+35)+SQR(
FVAR+36)+SQR(FVAR+37)+SQR(FVAR+38)+SQR(FVAR+39)+SQR(FVAR+40)+SQR(FVAR+41)+SQR
(FVAR+42)+SQR(FVAR+43)+SQR(FVAR+44)+SQR(FVAR+45)+SQR(FVAR+46)+SQR(FVAR+47)+SQ
R(FVAR+48)+SQR(FVAR+49)+SQR(FVAR+50)+SQR(FVAR+51)+SQR(FVAR+52)+SQR(FVAR+53)+S
QR(FVAR+54)+SQR(FVAR+55)+SQR(FVAR+56)+SQR(FVAR+57)+SQR(FVAR+58)+SQR(FVAR+59)+
SQR(FVAR+60)+SQR(FVAR+61)+SQR(FVAR+62)+SQR(FVAR+63)+SQR(FVAR+64)+SQR(FVAR+65)
+SQR(FVAR+66)+SQR(FVAR+67)+SQR(FVAR+68)+SQR(FVAR+69)+SQR(FVAR+70)+SQR(FVAR+71
)+SQR(FVAR+72)+SQR(FVAR+73)+SQR(FVAR+74)+SQR(FVAR+75)+SQR(FVAR+76)+SQR(FVAR+7
7)+SQR(FVAR+78)+SQR(FVAR+79)+SQR(FVAR+80)+SQR(FVAR+81)+SQR(FVAR+82)+SQR(FVAR+
83)+SQR(FVAR+84)+SQR(FVAR+85)+SQR(FVAR+86)+SQR(FVAR+87)+SQR(FVAR+88)+SQR(FVAR
+89)+SQR(FVAR+90)+SQR(FVAR+91)+SQR(FVAR+92)+SQR(FVAR+93)+SQR(FVAR+94)+SQR(FVA
R+95)+SQR(FVAR+96)+SQR(FVAR+97)+SQR(FVAR+98)+SQR(FVAR+99)+SQR(FVAR+100)-700)

and as you can see, both FNROOT and VAL have no problem in dealing with expressions of any length whatsoever, they're limited only by available RAM, not by the 96-character limit of the command-line itself. The same is true of INTEGRAL.

An alternative for the second command line would be the following:

      >FNROOT(0,0,VAL(T$[2])-700)

which is a slightly shorter (just 6 characters less) but much slower. Matter of fact the first version is 2.2 times faster, the reason being that the first expression parses the long expression to evaluate only once, then has FNROOT working with the parsed expression, while the second version has FNROOT executing VAL repeatedly as many times as needed to find and refine the root and thus parsing the long string multiple times.

J-F also managed to find a nice solution within the requirements (except for the fact that he uses initial guesses different from 0, which was also a requirement but that would be nitpicking) but as he uses a user-code loop within a loop it is much slower than using the assembly-language FNROOT and VAL applied to an expression parsed once into fast internal format. Anyway, congratulations to J-F for his very clever way to achieving the stated goal.

Just for fun and to demonstrate this no-limits capability even further, solving the following equation:

      Sqrt(x+1) + Sqrt(x+2) + Sqrt(x+3) + ... + Sqrt(x+98) + Sqrt(x+99) + Sqrt(x+200) = 2018

entails executing these command lines (118 character in all):

      >DESTROY ALL @ DIM T$[2800] @ FOR I=1 TO 200 @ T$=T$&"+SQR(FVAR+"&STR$(I)&")" @ NEXT I
      >VAL("FNROOT(0,0,"&T$[2]&"-2018)")

            10.4122270141
(correct 12-digit value: 10.4122270160)

and this time the expression which VAL evaluates is the 2708-character string:

FNROOT(0,0,SQR(FVAR+1)+SQR(FVAR+2)+SQR(FVAR+3)+SQR(FVAR+4)+SQR(FVAR+5)+SQR(F
VAR+6)+SQR(FVAR+7)+SQR(FVAR+8)+SQR(FVAR+9)+SQR(FVAR+10)+SQR(FVAR+11)+SQR(FVAR
+12)+SQR(FVAR+13)+SQR(FVAR+14)+SQR(FVAR+15)+SQR(FVAR+16)+SQR(FVAR+17)+SQR(FVA
R+18)+SQR(FVAR+19)+SQR(FVAR+20)+SQR(FVAR+21)+SQR(FVAR+22)+SQR(FVAR+23)+SQR(FV
AR+24)+SQR(FVAR+25)+SQR(FVAR+26)+SQR(FVAR+27)+SQR(FVAR+28)+SQR(FVAR+29)+SQR(F
VAR+30)+SQR(FVAR+31)+SQR(FVAR+32)+SQR(FVAR+33)+SQR(FVAR+34)+SQR(FVAR+35)+SQR(
FVAR+36)+SQR(FVAR+37)+SQR(FVAR+38)+SQR(FVAR+39)+SQR(FVAR+40)+SQR(FVAR+41)+SQR
(FVAR+42)+SQR(FVAR+43)+SQR(FVAR+44)+SQR(FVAR+45)+SQR(FVAR+46)+SQR(FVAR+47)+SQ
R(FVAR+48)+SQR(FVAR+49)+SQR(FVAR+50)+SQR(FVAR+51)+SQR(FVAR+52)+SQR(FVAR+53)+S
QR(FVAR+54)+SQR(FVAR+55)+SQR(FVAR+56)+SQR(FVAR+57)+SQR(FVAR+58)+SQR(FVAR+59)+
SQR(FVAR+60)+SQR(FVAR+61)+SQR(FVAR+62)+SQR(FVAR+63)+SQR(FVAR+64)+SQR(FVAR+65)
+SQR(FVAR+66)+SQR(FVAR+67)+SQR(FVAR+68)+SQR(FVAR+69)+SQR(FVAR+70)+SQR(FVAR+71
)+SQR(FVAR+72)+SQR(FVAR+73)+SQR(FVAR+74)+SQR(FVAR+75)+SQR(FVAR+76)+SQR(FVAR+7
7)+SQR(FVAR+78)+SQR(FVAR+79)+SQR(FVAR+80)+SQR(FVAR+81)+SQR(FVAR+82)+SQR(FVAR+
83)+SQR(FVAR+84)+SQR(FVAR+85)+SQR(FVAR+86)+SQR(FVAR+87)+SQR(FVAR+88)+SQR(FVAR
+89)+SQR(FVAR+90)+SQR(FVAR+91)+SQR(FVAR+92)+SQR(FVAR+93)+SQR(FVAR+94)+SQR(FVA
R+95)+SQR(FVAR+96)+SQR(FVAR+97)+SQR(FVAR+98)+SQR(FVAR+99)+SQR(FVAR+100)+SQR(F
VAR+101)+SQR(FVAR+102)+SQR(FVAR+103)+SQR(FVAR+104)+SQR(FVAR+105)+SQR(FVAR+106
)+SQR(FVAR+107)+SQR(FVAR+108)+SQR(FVAR+109)+SQR(FVAR+110)+SQR(FVAR+111)+SQR(F
VAR+112)+SQR(FVAR+113)+SQR(FVAR+114)+SQR(FVAR+115)+SQR(FVAR+116)+SQR(FVAR+117
)+SQR(FVAR+118)+SQR(FVAR+119)+SQR(FVAR+120)+SQR(FVAR+121)+SQR(FVAR+122)+SQR(F
VAR+123)+SQR(FVAR+124)+SQR(FVAR+125)+SQR(FVAR+126)+SQR(FVAR+127)+SQR(FVAR+128
)+SQR(FVAR+129)+SQR(FVAR+130)+SQR(FVAR+131)+SQR(FVAR+132)+SQR(FVAR+133)+SQR(F
VAR+134)+SQR(FVAR+135)+SQR(FVAR+136)+SQR(FVAR+137)+SQR(FVAR+138)+SQR(FVAR+139
)+SQR(FVAR+140)+SQR(FVAR+141)+SQR(FVAR+142)+SQR(FVAR+143)+SQR(FVAR+144)+SQR(F
VAR+145)+SQR(FVAR+146)+SQR(FVAR+147)+SQR(FVAR+148)+SQR(FVAR+149)+SQR(FVAR+150
)+SQR(FVAR+151)+SQR(FVAR+152)+SQR(FVAR+153)+SQR(FVAR+154)+SQR(FVAR+155)+SQR(F
VAR+156)+SQR(FVAR+157)+SQR(FVAR+158)+SQR(FVAR+159)+SQR(FVAR+160)+SQR(FVAR+161
)+SQR(FVAR+162)+SQR(FVAR+163)+SQR(FVAR+164)+SQR(FVAR+165)+SQR(FVAR+166)+SQR(F
VAR+167)+SQR(FVAR+168)+SQR(FVAR+169)+SQR(FVAR+170)+SQR(FVAR+171)+SQR(FVAR+172
)+SQR(FVAR+173)+SQR(FVAR+174)+SQR(FVAR+175)+SQR(FVAR+176)+SQR(FVAR+177)+SQR(F
VAR+178)+SQR(FVAR+179)+SQR(FVAR+180)+SQR(FVAR+181)+SQR(FVAR+182)+SQR(FVAR+183
)+SQR(FVAR+184)+SQR(FVAR+185)+SQR(FVAR+186)+SQR(FVAR+187)+SQR(FVAR+188)+SQR(F
VAR+189)+SQR(FVAR+190)+SQR(FVAR+191)+SQR(FVAR+192)+SQR(FVAR+193)+SQR(FVAR+194
)+SQR(FVAR+195)+SQR(FVAR+196)+SQR(FVAR+197)+SQR(FVAR+198)+SQR(FVAR+199)+SQR(F
VAR+200)-2018)


which is quite a sight to behold.

Lessons learnt:

      - That VAL and FNROOT (and INTEGRAL) can deal with expressions limited only by available RAM, not by the 96-character limit of the command line.

Step the Fourth:

"Write a program which accepts a positive integer N from the user and outputs both the number and its square for every value from N down to 0, both included, one pair per line."


As J-F wrote in his nice solution, the task would be utterly trivial were it not for the no-variables requirement. My original solution is this 2-line (46 bytes) program:

      1 DISP USING "#,^";(VAL(DISP$)+1)^2
      2 DISP SQR(RES)-1,RES^2 @ IF SQR(RES) THEN 2

Let's see:

      >15 [RUN]

       15       225
       14       196
       13       169
       ...

       3       9
       2       4
       1       1
       0       0


The trick to avoid using variables is first of all to accept a value from the user directly from the command line using DISP$, instead of inputting it to a variable, and then to store and handle it using RES, a system location which stores the value of the most recently evaluated *or displayed* numeric expression (whether real- or complex-valued but not string-valued).

Thus, the first line simply puts in RES an adequate initial value for the loop in the second line by simply displaying it. Normally this would result in this spurious initial value being displayed too, as a side effect, but this is avoided by the USING image which supresses both the value and the return carriage.

The second line then enters a simple loop where SQR(RES)-1 retrieves and displays the next value to square and RES^2 squares it and displays the result as well. As soon as SQR(RES) reaches 0, the loop (and the program) ends. Notice that IF does *not* update the value of RES to the expression being evaluated and tested.

By the way, there's another 1-line version which is 49 bytes instead of 46:

      1 DISP USING "#,^";(VAL(DISP$)+1)^2 @ 'A': DISP SQR(RES)-1,RES^2 @ IF SQR(RES) THEN 'A'

It simply uses a local label 'A' midline to implement the loop instead of a line number, thus avoiding the use of a second line.

Lessons learnt:

      - that RES can be used to occasionally replace a variable
      - that USING a image we can store a value in RES without actually displaying it
      - that a local label midline allows looping within part of a single line

Step the Fifth:

"Write a program which accepts from the user a single-digit Id, then accepts from the user a text to scan for said Id and output the name associated with that Id.

The format of the text to scan (up to 80 characters long, say) is as follows:

      (Id1):(Name1),(Id2):(Name2), ... , (IdN):(NameN)

where (Id) is a single digit and (Name) is a string of up to 30 characters A-Z & spaces. The Id aren't necessarily in numerical order in the text, but the Id sought for must appear somewhere within the text."


This is similar in spirit to Step 4 above but with the added difficulty of having to handle two inputs (the Id to search for and the text where to search for it) without using variables. My original solution is a 2-line program (74 bytes) but as no one posted any code or comment for this Step, it will be reserved for possible use at some future time.

Step the Sixth:

"We'll call "Selfie" to any positive N-digit integer number which has the property that if you sum its N digits raised to the Nth power you get the original number backwards. For instance, the 7-digit number 5271471 is a Selfie:

      5271471 => 5^7 + 2^7 + 7^7 + 1^7 + 4^7 + 7^7 + 1^7 = 1741725, which is 5271471 backwards

Write a program to find all Selfies from 1 to 9 digits long (for 10-digit HP calcs, 29 in all) or from 1 to 11 digits long (for 12-digit HP calcs, 37 in all). 0 is not a positive number so it's not a Selfie."


Same here, no one posted any code or comments for this one either so I'll also save my original solution for a future article or something. As I said at the beginning of this post, it's a real pity as this Step was solvable (partially or in full) using most any HP calc model, and there are at least 3 ways to handle it, including brute force which will quickly become unfeasible as for 11-digit numbers there would be some 90 billion numbers to try, so more sophisticated techniques are required to reach that far in reasonable times (a few minutes).

By the way, I didn't ask for 12/10-digit solutions because for some 12/10-digit numbers the sum of their digits raised to the 12th/10th power exceeds the 12/10-digit range. Also, there are no 12-digit Selfies (but there's a unique 10-digit one).

That's all for now.
Regards.
V.

  
Find All My HP-related Materials here:  Valentin Albillo's HP Collection
 
Visit this user's website Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
[VA] Short & Sweet Math Challenges #23 - My Solutions & Comments - Valentin Albillo - 05-10-2018 09:55 PM



User(s) browsing this thread: 1 Guest(s)