Prev: 343C Up: Map Next: 346A
3449: THE 'SERIES GENERATOR' SUBROUTINE (offset +3E)
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.
Input
A Series parameter (+06, +08 or +0C)
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)
3459 DEFB $38 end_calc
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.
345D CALL GEN_ENT_2
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)
3465 DEFB $EE
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)
3468 DEFB $38 end_calc
3469 RET Finished.
Prev: 343C Up: Map Next: 346A