This is a follow up on an archived message:
http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/archv015.cgi?read=72151
I've ported my algorithm to my trusty TI-95 PROCALC, a machine I baught when they still were in the shops.
If you own the PC-Interface, you can compile the source with TIC95.EXE and load it into your calc.
The program presents a menu with 4 selections:
F1:GO Run the loop
F2:TST Run a single test on one number, displays the smallest digit.
F3:DIG Set number of different digits (2 or 3), 2 is default
F4:BEG Set beginning of loop, default is 33334.
For F3/F4, you have to enter the number and then press the key.
The most interesting result for me was that the TI-95 is noticably faster than my HP 42 (some 10 to 20% percieved).
The algorithm is essentially the same. The programming model in both calcs is comparable. TI's comparison statements work against registers (no longer the "t" register only). In many cases I had to store a value in a register on the TI where I could use the stack on the HP. Registers can be accessed by letters but this is just a shorthand notation to the corresponding numbers (RCL 000 is the same as RCL A).
The flags are used just the opposite way in my HP implementation and in this program: On the HP, I reset a flag when a corresponding digit is found while I set a flag on the TI. The reason is simple: the HP has a FC?C instruction that tests and clears a flag in one step. The feature is missing on the TI so I could use the more natural approach of setting the flags instead or clearing them.
Another missing feature on the TI is MOD: I had to use a more complicated formula to get the last digit.
Some statements can only be entered in so called unprotected (system) mode. These are SBA 226, a call to an assembly routine which does a VIEW (not available on the keyboard), and STB 00xx, which stores a byte in memory. The latter is used to clear the flags.
After entering the program you can speed it up with the ASM key: it replaces all (slow) label jumps by absolute jumps. INV ASM undoes the change.
Here is the program:
'
' Find 10 digit squares with at most 2 or 3 different digits
'
DFN CLR
DFN F1:GO @GO ' Start computation
DFN F2:TST@TT ' Test a single value
DFN F3:DIG@DD ' Set # of different digits (2, 3)
DFN F4:BEG@BB ' Set first guess
2
SBL DD ' Default: 2 different digits
33334
SBL BB ' First guess to square & test
CLR
HLTLBL AA ' check a value against # of digits
INC H ' some statistics
SBA 226 ' display without delay
STO A ' scratch register for value
0
STB 0028 ' system register: Flags 0-7
STB 0029 ' system register: Flags 8-15
STO C ' clear # of digits found so far
LBL A1
( ' compute A MOD 10 and INT( A / 10 )
RCL A
-
(
/
1
0
)
INT
STO A ' this is INT( A / 10 )
*
10
) ' this is A MOD 10 (last digit of number)
STO B ' use B for indirect flag setting
INV TF IND B
INC C ' digit not yet encounterd, count it
SF IND B ' mark digit
RCL C ' get count
IF> D ' compare to maximum digits
SF 00 ' too many digits
TF 00 ' tested number has failed
RTN ' (0 encountered or too many digits)
0 ' all digits tested?
IF= A
RTN ' done
GTL A1 ' next digitLBL CC ' get smallest valid digit for next guess
RCL C ' # of digits found
IF= D ' is the allowed maximum?
GTL C1 ' find the smallest digit encounterd
1 ' not all allowed digits in last try
RTN ' must return 1
LBL C1
1 ' digit index starts with 1
STO B
LBL C2
TF IND B ' is digit in last tested number?
RTN ' yes, must be the smallest
INC B ' next digit
RCL B ' get it (in case of return)
GTL C2 ' loopLBL DD ' store # of allowed digits (key F3)
STO D
RTNLBL BB ' store first number to square
STO E ' compensate for INC E in main loop
INV INC E
0 ' initialize counters and comparison values
STO F ' first 4 digits
STO G ' first 3 digits
STO H ' total # of checks
RTNLBL GO ' main loop starts here (key F1)
INC E ' next # to square
99999 ' check end of loop
INV IF> E
GTL ZZ ' done
( ' compute first 4 digits of squared #
RCL E
x^2
/
1000000
)
INT
INV IF= F ' same 4 digits as last try?
SBL FF ' no, get next guess based on first 4 digits
RCL E ' get number again
x^2 ' and square it
SBL AA ' digit test routine
INV TF 00 ' check it test passed
SBL PR ' got it, show/print result
GTL GO ' next guessLBL FF ' find a new guess based on first 4 digits
STO F
LBL F1
RCL F ' 4 digits to test
( ' check if first 3 digits have changed
/
10
)
INT
INV IF= G
SBL GG ' check first 3 digits first
RCL F ' get current guess
SBL AA ' test it
INV TF 00
GTL F2 ' test passed: compute new guess for main loop
INC F ' test failed, try next 4 digit number
GTL F1
LBL F2 ' compute a new guess
(
(
RCL F ' first 4
*
10 ' shifted 1 left
+
SBL CC ' add smallest possible next digit
)
*
100000 ' shift 5 left
+
11110 ' offset which can be added safely
)
SQR ' the INT of the square root is next guess
INT
STO E ' store it
INC E ' our guess was still too small
RTNLBL GG ' find a new guess based on first 3 digits
STO G ' 3 digits to test
LBL G1
RCL G ' get current guess
SBL AA ' test it
INV TF 00
GTL G2 ' test passed: compute new guess for FF loop
INC G ' test failed, try next 3 digit number
GTL G1
LBL G2 ' compute a new guess
(
RCL G ' first 3
*
10 ' shifted 1 left
+
SBL CC ' add smallest possible next digit
)
STO F ' store it
RTNLBL PR ' print or show a valid result
RCL E ' number to be squared
PRT
x~t ' save in t-Register
RCL E
x^2 ' squared number in display
PRT
INV TF 74
BRK ' halt if no printer connected
RCL C ' number of different digits
PRT
( ' flag word
RCB 0028
+
RCB 0029
*
256
)
HEX ' print it in HEX
PRT
DEC ' revert to normal display
RTNLBL TT ' test a single value (key F2)
SBL AA ' call test routine
0
TF 00
HLT ' stop and show 0 if test failed
SBL CC ' show smallest digit or 1 if less then
HLT ' the allowed number were foundLBL ZZ ' end of main loop
RCL H ' show number of checks
PRT
HLT
END