Prev: 300F Up: Map Next: 30A9
3014: THE 'ADDITION' OPERATION (offset +0F)
The address of this routine is found in the table of addresses. It is called via the calculator literal +0F by the routines at BEEP, NEXT, CIRCLE, DRAW, CD_PRMS1, S_RND, DEC_TO_FP, INT_TO_FP, FP_TO_BC, series, exp, ln, get_argt, sin, atn and asn. It is also called indirectly via fp_calc_2, and the routine at subtract continues here.
The first of three major arithmetical subroutines, this subroutine carries out the floating-point addition of two numbers, each with a 4-byte mantissa and a 1-byte exponent. In these three subroutines, the two numbers at the top of the calculator stack are added/multiplied/divided to give one number at the top of the calculator stack, a 'last value'.
HL points to the second number from the top, the augend/multiplier/dividend. DE points to the number at the top of the calculator stack, the addend/multiplicand/divisor. Afterwards HL points to the resultant 'last value' whose address can also be considered to be STKEND-5.
But the addition subroutine first tests whether the 2 numbers to be added are 'small integers'. If they are, it adds them quite simply in HL and BC, and puts the result directly on the stack. No two's complementing is needed before or after the addition, since such numbers are held on the stack in two's complement form, ready for addition.
Input
DE Address of the first byte of the addend/multiplicand/divisor
HL Address of the first byte of the augend/multiplier/dividend
Output
addition 3014 LD A,(DE) Test whether the first bytes of both numbers are zero.
3015 OR (HL)
3016 JR NZ,FULL_ADDN If not, jump for full addition.
3018 PUSH DE Save the pointer to the second number.
3019 INC HL Point to the second byte of the first number and save that pointer too.
301A PUSH HL
301B INC HL Point to the less significant byte.
301C LD E,(HL) Fetch it in E.
301D INC HL Point to the more significant byte.
301E LD D,(HL) Fetch it in D.
301F INC HL Move on to the second byte of the second number.
3020 INC HL
3021 INC HL
3022 LD A,(HL) Fetch it in A (this is the sign byte).
3023 INC HL Point to the less significant byte.
3024 LD C,(HL) Fetch it in C.
3025 INC HL Point to the more significant byte.
3026 LD B,(HL) Fetch it in B.
3027 POP HL Fetch the pointer to the sign byte of the first number; put it in DE, and the number in HL.
3028 EX DE,HL
3029 ADD HL,BC Perform the addition: result in HL.
302A EX DE,HL Result to DE, sign byte to HL.
302B ADC A,(HL) Add the sign bytes and the carry into A; this will detect any overflow.
302C RRCA
302D ADC A,$00 A non-zero A now indicates overflow.
302F JR NZ,ADDN_OFLW Jump to reset the pointers and to do full addition.
3031 SBC A,A Define the correct sign byte for the result.
3032 LD (HL),A Store it on the stack.
3033 INC HL Point to the next location.
3034 LD (HL),E Store the low byte of the result.
3035 INC HL Point to the next location.
3036 LD (HL),D Store the high byte of the result.
3037 DEC HL Move the pointer back to address the first byte of the result.
3038 DEC HL
3039 DEC HL
303A POP DE Restore STKEND to DE.
303B RET Finished.
Note that the number -65536 can arise here in the form 00 FF 00 00 00 as the result of the addition of two smaller negative integers, e.g. -65000 and -536. It is simply stacked in this form. This is a mistake. The Spectrum system cannot handle this number.
Most functions treat it as zero, and it is printed as -1E-38, obtained by treating is as 'minus zero' in an illegitimate format.
One possible remedy would be to test for this number at about byte 3032 and, if it is present, to make the second byte +80 and the first byte +91, so producing the full five-byte floating-point form of the number, i.e. 91 80 00 00 00, which causes no problems. See also the remarks in 'truncate'.
ADDN_OFLW 303C DEC HL Restore the pointer to the first number.
303D POP DE Restore the pointer to the second number.
FULL_ADDN 303E CALL RE_ST_TWO Re-stack both numbers in full five-byte floating-point form.
The full addition subroutine first calls PREP_ADD for each number, then gets the two numbers from the calculator stack and puts the one with the smaller exponent into the addend position. It then calls SHIFT_FP to shift the addend up to 32 decimal places right to line it up for addition. The actual addition is done in a few bytes, a single shift is made for carry (overflow to the left) if needed, the result is two's complemented if negative, and any arithmetic overflow is reported; otherwise the subroutine jumps to TEST_NORM to normalise the result and return it to the stack with the correct sign bit inserted into the second byte.
3041 EXX Exchange the registers.
3042 PUSH HL Save the next literal address.
3043 EXX Exchange the registers.
3044 PUSH DE Save pointer to the addend.
3045 PUSH HL Save pointer to the augend.
3046 CALL PREP_ADD Prepare the augend.
3049 LD B,A Save its exponent in B.
304A EX DE,HL Exchange the pointers.
304B CALL PREP_ADD Prepare the addend.
304E LD C,A Save its exponent in C.
304F CP B If the first exponent is smaller, keep the first number in the addend position; otherwise change the exponents and the pointers back again.
3050 JR NC,SHIFT_LEN
3052 LD A,B
3053 LD B,C
3054 EX DE,HL
SHIFT_LEN 3055 PUSH AF Save the larger exponent in A.
3056 SUB B The difference between the exponents is the length of the shift right.
3057 CALL FETCH_TWO Get the two numbers from the stack.
305A CALL SHIFT_FP Shift the addend right.
305D POP AF Restore the larger exponent.
305E POP HL HL is to point to the result.
305F LD (HL),A Store the exponent of the result.
3060 PUSH HL Save the pointer again.
3061 LD L,B M4 to H and M5 to L (see FETCH_TWO).
3062 LD H,C
3063 ADD HL,DE Add the two right bytes.
3064 EXX N2 to H' and N3 to L' (see FETCH_TWO).
3065 EX DE,HL
3066 ADC HL,BC Add left bytes with carry.
3068 EX DE,HL Result back in D'E'.
3069 LD A,H Add H', L' and the carry; the resulting mechanisms will ensure that a single shift right is called if the sum of 2 positive numbers has overflowed left, or the sum of 2 negative numbers has not overflowed left.
306A ADC A,L
306B LD L,A
306C RRA
306D XOR L
306E EXX
306F EX DE,HL The result is now in DED'E'.
3070 POP HL Get the pointer to the exponent.
3071 RRA The test for shift (H', L' were +00 for positive numbers and +FF for negative numbers).
3072 JR NC,TEST_NEG
3074 LD A,$01 A counts a single shift right.
3076 CALL SHIFT_FP The shift is called.
3079 INC (HL) Add 1 to the exponent; this may lead to arithmetic overflow.
307A JR Z,ADD_REP_6
TEST_NEG 307C EXX Test for negative result: get sign bit of L' into A (this now correctly indicates the sign of the result).
307D LD A,L
307E AND $80
3080 EXX
3081 INC HL Store it in the second byte position of the result on the calculator stack.
3082 LD (HL),A
3083 DEC HL
3084 JR Z,GO_NC_MLT If it is zero, then do not two's complement the result.
3086 LD A,E Get the first byte.
3087 NEG Negate it.
3089 CCF Complement the carry for continued negation, and store byte.
308A LD E,A
308B LD A,D Get the next byte.
308C CPL One's complement it.
308D ADC A,$00 Add in the carry for negation.
308F LD D,A Store the byte.
3090 EXX Proceed to get next byte into the A register.
3091 LD A,E
3092 CPL One's complement it.
3093 ADC A,$00 Add in the carry for negation.
3095 LD E,A Store the byte.
3096 LD A,D Get the last byte.
3097 CPL One's complement it.
3098 ADC A,$00 Add in the carry for negation.
309A JR NC,END_COMPL Done if no carry.
309C RRA Else, get .5 into mantissa and add 1 to the exponent; this will be needed when two negative numbers add to give an exact power of 2, and it may lead to arithmetic overflow.
309D EXX
309E INC (HL)
ADD_REP_6 309F JP Z,REPORT_6 Give the error if required.
30A2 EXX
END_COMPL 30A3 LD D,A Store the last byte.
30A4 EXX
GO_NC_MLT 30A5 XOR A Clear A and the carry flag.
30A6 JP TEST_NORM Exit via TEST_NORM.
Prev: 300F Up: Map Next: 30A9