Prev: 31AF Up: Map Next: 3293
3214: THE 'INTEGER TRUNCATION TOWARDS ZERO' SUBROUTINE (offset +3A)
The address of this routine is found in the table of addresses. It is called via the calculator literal +3A by the routine at int.
This subroutine (say I(x)) returns the result of integer truncation of x, the 'last value', towards zero. Thus I(2.4) is 2 and I(-2.4) is -2. The subroutine returns at once if x is in the form of a 'short integer'. It returns zero if the exponent byte of x is less than +81 (ABS x is less than 1). If I(x) is a 'short integer' the subroutine returns it in that form. It returns x if the exponent byte is +A0 or greater (x has no significant non-integral part). Otherwise the correct number of bytes of x are set to zero and, if needed, one more byte is split with a mask.
Input
HL Address of the first byte of the number
truncate 3214 LD A,(HL) Get the exponent byte of x into A.
3215 AND A If A is zero, return since x is already a small integer.
3216 RET Z
3217 CP $81 Compare e, the exponent, to +81.
3219 JR NC,T_GR_ZERO Jump if e is greater than +80.
321B LD (HL),$00 Else, set the exponent to zero; enter +20 into A and jump forward to NIL_BYTES to make all the bits of x be zero.
321D LD A,$20
321F JR NIL_BYTES
T_GR_ZERO 3221 CP $91 Compare e to +91.
3223 JR NZ,T_SMALL Jump if e not +91.
The next 26 bytes seem designed to test whether x is in fact -65536, i.e. 91 80 00 00 00, and if it is, to set it to 00 FF 00 00 00. This is a mistake. As already stated, the Spectrum system cannot handle this number. The result here is simply to make INT (-65536) return the value -1. This is a pity, since the number would have been perfectly all right if left alone. The remedy would seem to be simply to omit the 28 bytes from 3223 above to 323E inclusive from the program.
3225 INC HL HL is pointed at the fourth byte of x, where the 17 bits of the integer part of x end after the first bit.
3226 INC HL
3227 INC HL
3228 LD A,$80 The first bit is obtained in A, using +80 as a mask.
322A AND (HL)
322B DEC HL That bit and the previous 8 bits are tested together for zero.
322C OR (HL)
322D DEC HL HL is pointed at the second byte of x.
322E JR NZ,T_FIRST If already non-zero, the test can end.
3230 LD A,$80 Otherwise, the test for -65536 is now completed: 91 80 00 00 00 will leave the zero flag set now.
3232 XOR (HL)
T_FIRST 3233 DEC HL HL is pointed at the first byte of x.
3234 JR NZ,T_EXPNENT If zero reset, the jump is made.
3236 LD (HL),A The first byte is set to zero.
3237 INC HL HL points to the second byte.
3238 LD (HL),$FF The second byte is set to +FF.
323A DEC HL HL again points to the first byte.
323B LD A,$18 The last 24 bits are to be zero.
323D JR NIL_BYTES The jump to NIL_BYTES completes the number 00 FF 00 00 00.
If the exponent byte of x is between +81 and +90 inclusive, I(x) is a 'small integer', and will be compressed into one or two bytes. But first a test is made to see whether x is, after all, large.
T_SMALL 323F JR NC,X_LARGE Jump with exponent byte +92 or more (it would be better to jump with +91 too).
3241 PUSH DE Save STKEND in DE.
3242 CPL Range 129<=A<=144 becomes 126>=A>=111.
3243 ADD A,$91 Range is now 15>=A>=0.
3245 INC HL Point HL at second byte.
3246 LD D,(HL) Second byte to D.
3247 INC HL Point HL at third byte.
3248 LD E,(HL) Third byte to E.
3249 DEC HL Point HL at first byte again.
324A DEC HL
324B LD C,$00 Assume a positive number.
324D BIT 7,D Now test for negative (bit 7 set).
324F JR Z,T_NUMERIC Jump if positive after all.
3251 DEC C Change the sign.
T_NUMERIC 3252 SET 7,D Insert true numeric bit, 1, in D.
3254 LD B,$08 Now test whether A>=8 (one byte only) or two bytes needed.
3256 SUB B
3257 ADD A,B Leave A unchanged.
3258 JR C,T_TEST Jump if two bytes needed.
325A LD E,D Put the one byte into E.
325B LD D,$00 And set D to zero.
325D SUB B Now 1<=A<=7 to count the shifts needed.
T_TEST 325E JR Z,T_STORE Jump if no shift needed.
3260 LD B,A B will count the shifts.
T_SHIFT 3261 SRL D Shift D and E right B times to produce the correct number.
3263 RR E
3265 DJNZ T_SHIFT Loop until B is zero.
T_STORE 3267 CALL INT_STORE Store the result on the stack.
326A POP DE Restore STKEND to DE.
326B RET Finished.
Large values of x remain to be considered.
T_EXPNENT 326C LD A,(HL) Get the exponent byte of x into A.
X_LARGE 326D SUB $A0 Subtract +A0 from e.
326F RET P Return on plus - x has no significant non-integral part. (If the true exponent were reduced to zero, the 'binary point' would come at or after the end of the four bytes of the mantissa.)
3270 NEG Else, negate the remainder; this gives the number of bits to become zero (the number of bits after the 'binary point').
Now the bits of the mantissa can be cleared.
NIL_BYTES 3272 PUSH DE Save the current value of DE (STKEND).
3273 EX DE,HL Make HL point one past the fifth byte.
3274 DEC HL HL now points to the fifth byte of x.
3275 LD B,A Get the number of bits to be set to zero in B and divide it by 8 to give the number of whole bytes implied.
3276 SRL B
3278 SRL B
327A SRL B
327C JR Z,BITS_ZERO Jump forward if the result is zero.
BYTE_ZERO 327E LD (HL),$00 Else, set the bytes to zero; B counts them.
3280 DEC HL
3281 DJNZ BYTE_ZERO
BITS_ZERO 3283 AND $07 Get A (mod 8); this is the number of bits still to be set to zero.
3285 JR Z,IX_END Jump to the end if nothing more to do.
3287 LD B,A B will count the bits now.
3288 LD A,$FF Prepare the mask.
LESS_MASK 328A SLA A With each loop a zero enters the mask from the right and thereby a mask of the correct length is produced.
328C DJNZ LESS_MASK
328E AND (HL) The unwanted bits of (HL) are lost as the masking is performed.
328F LD (HL),A
IX_END 3290 EX DE,HL Return the pointer to HL.
3291 POP DE Return STKEND to DE.
3292 RET Finished.
Prev: 31AF Up: Map Next: 3293