|Prev: 343C||Up: Map||Next: 346A|
The address of this routine is found in the table of addresses. It is called via a calculator literal (+86, +88 or +8C) by the routines at exp, ln, sin and atn.
This important subroutine generates the series of Chebyshev polynomials which are used to approximate to SIN, ATN, LN and EXP and hence to derive the other arithmetic functions which depend on these (COS, TAN, ASN, ACS, ** and SQR).
The polynomials are generated, for n=1, 2, etc. by the recurrence relation Tn+1(z)=2zTn(z)-Tn-1(z), where Tn(z) is the nth Chebyshev polynomial in z.
The series in fact generates T0, 2T1, 2T2, ..., 2Tn-1, where n is 6 for SIN, 8 for EXP, and 12 for LN and ATN.
The coefficients of the powers of z in these polynomials may be found in the Handbook of Mathematical Functions by M. Abramowitz and I. A. Stegun (Dover 1965), page 795.
In simple terms this subroutine is called with the 'last value' on the calculator stack, say Z, being a number that bears a simple relationship to the argument, say X, when the task is to evaluate, for instance, SIN X. The calling subroutine also supplies the list of constants that are to be required (six constants for SIN). The series generator then manipulates its data and returns to the calling routine a 'last value' that bears a simple relationship to the requested function, for instance, SIN X.
This subroutine can be considered to have four major parts.
i. The setting of the loop counter. The calling subroutine passes its parameters in the A register for use as a counter. The calculator is entered at GEN_ENT_1 so that the counter can be set.
|series||3449||LD B,A||Move the parameter to B.|
|344A||CALL GEN_ENT_1||In effect a RST $28 instruction but sets the counter.|
ii. The handling of the 'last value', Z. The loop of the generator requires 2*Z to be placed in mem-0, zero to be placed in mem-2 and the 'last value' to be zero.
|344D||DEFB $31||duplicate: Z, Z|
|344E||DEFB $0F||addition: 2*Z|
|344F||DEFB $C0||st_mem_0: 2*Z (mem-0 holds 2*Z)|
|3450||DEFB $02||delete: -|
|3451||DEFB $A0||stk_zero: 0|
|3452||DEFB $C2||st_mem_2: 0 (mem-2 holds 0)|
iii. The main loop.
The series is generated by looping, using BREG as a counter; the constants in the calling subroutine are stacked in turn by calling stk_data; the calculator is re-entered at GEN_ENT_2 so as not to disturb the value of BREG; and the series is built up in the form:
B(R)=2*Z*B(R-1)-B(R-2)+A(R), for R=1, 2, ..., N, where A(1), A(2)...A(N) are the constants supplied by the calling subroutine (SIN, ATN, LN and EXP) and B(0)=0=B(-1).
The (R+1)th loop starts with B(R) on the stack and with 2*Z, B(R-2) and B(R-1) in mem-0, mem-1 and mem-2 respectively.
|G_LOOP||3453||DEFB $31||duplicate: B(R), B(R)|
|3454||DEFB $E0||get_mem_0: B(R), B(R), 2*Z|
|3455||DEFB $04||multiply: B(R), 2*B(R)*Z|
|3456||DEFB $E2||get_mem_2: B(R),2*B(R)*Z, B(R-1)|
|3457||DEFB $C1||st_mem_1: mem-1 holds B(R-1)|
|3458||DEFB $03||subtract: B(R), 2*B(R)*Z-B(R-1)|
The next constant is placed on the calculator stack.
|345A||CALL stk_data||B(R), 2*B(R)*Z-B(R-1), A(R+1)|
The calculator is re-entered without disturbing BREG.
|3460||DEFB $0F||addition: B(R), 2*B(R)*Z-B(R-1)+A(R+1)|
|3461||DEFB $01||exchange: 2*B(R)*Z-B(R-1)+A(R+1), B(R)|
|3462||DEFB $C2||st_mem_2: mem-2 holds B(R)|
|3463||DEFB $02||delete: 2*B(R)*Z-B(R-1)+A(R+1)=B(R+1)|
|3464||DEFB $35||dec_jr_nz to G_LOOP: B(R+1)|
iv. The subtraction of B(N-2). The loop above leaves B(N) on the stack and the required result is given by B(N)-B(N-2).
|3466||DEFB $E1||get_mem_1: B(N), B(N-2)|
|3467||DEFB $03||subtract: B(N)-B(N-2)|
|Prev: 343C||Up: Map||Next: 346A|