home *** CD-ROM | disk | FTP | other *** search
-
- ; *******************************************************
- ; * *
- ; * Turbo Pascal Runtime Library Version 7.0 *
- ; * Real Round/Trunc *
- ; * *
- ; * Copyright (C) 1989-1993 Norbert Juffa *
- ; * *
- ; *******************************************************
-
- TITLE FPRND
-
-
- CODE SEGMENT BYTE PUBLIC
-
- ASSUME CS:CODE
-
- ; Externals
- EXTRN HaltError:NEAR
-
- ; Publics
-
- PUBLIC RealTrunc,RTrunc,RRound
-
- ;-------------------------------------------------------------------------------
- ; RealTrunc converts a TURBO-Pascal six byte floatingpoint number to a four
- ; byte signed integer. Truncation or rounding can be requested by the caller
- ; by setting a flag. If the conversion results in a long integer overflow, the
- ; routine returns with the carry flag set. When rounding is selected, the
- ; routine complies with the IEEE "round to nearest or even" mode. For example,
- ; Round (4.5) = 4, but Round (5.5) = 6. Special care is taken to accomodate
- ; correct handling of the smallest LONGINT number 8000000h.
- ;
- ; INPUT: DX:BX:AX floating point number
- ; CH rounding flag ( 0 = trunc, all others = round)
- ;
- ; OUTPUT: DX:AX converted longint number
- ; CF set if overflow occured
- ;
- ; DESTROYS: AX,BX,CX,DX,Flags
- ;-------------------------------------------------------------------------------
-
- $long_zero: XOR AX, AX ; load
- CWD ; zero into DX:AX
- RETN ; exit
- $too_big: JNZ $ovrfl_err2 ; abs (number) > 2^32
- CMP DH, 80h ; num negative && abs (num) < 2^32-2^24 ?
- JNE $ovrfl_err2 ; no, overflow
- XOR AL, AL ; clear sticky flag
- PUSH DX ; save original sign
- OR DH, 80h ; set hidden bit
- JMP $shft_done ; too big numbers caught by 2nd check
- $ovrfl_err2: STC ; signal error
- RETN ; exit
-
- ALIGN 4
-
- RealTrunc PROC NEAR
- ADD AL, 60h ; number to big ?
- JC $too_big ; probably, do detailed check
- CMP AL, 0E0h ; number < 0.5 ?
- JB $long_zero ; return zero
- $size_ok: PUSH DX ; save sign
- OR DH, 80h ; set implicit mantissa bit
- MOV CL, AL ; counter
- XOR AL, AL ; initialize sticky flag
- CMP CL, -16 ; 16-bit shift possible ?
- JA $byte_shift ; no, try 8-bit shift
- OR AL, AH ; accumulate
- OR AL, BL ; sticky flag
- MOV AH, BH ; shift DX:BX:AH
- MOV BX, DX ; 16 bits to
- XOR DX, DX ; the right
- ADD CL, 16 ; remaining bit shifts
- JZ $shft_done ; no shifts left, ->
- $byte_shift: CMP CL, -8 ; 8-bit shift possible ?
- JA $4bit_shift ; no, try nibble shift
- OR AL, AH ; accumulate sticky flag
- MOV AH, BL ; shift
- MOV BL, BH ; DX:BX:AH
- MOV BH, DL ; 8 bits
- MOV DL, DH ; to the
- XOR DH, DH ; right
- ADD CL, 8 ; remaining bit shifts
- JZ $shft_done ; no bit shifts left
- $4bit_shift: NEG AL ; sticky flag <> 0 ?
- SBB AL, AL ; set to FFh if not 0
- CMP CL, -4 ; nibble shift possible ?
- JA $bit_shift ; no, try single bit shifts
- SHR DX, 1 ; shift DX:BX:AH
- RCR BX, 1 ; 1 bit to
- RCR AX, 1 ; the right and accumulate sticky flag
- SHR DX, 1 ; shift DX:BX:AH
- RCR BX, 1 ; 1 bit to
- RCR AX, 1 ; the right and accumulate sticky flag
- SHR DX, 1 ; shift DX:BX:AH
- RCR BX, 1 ; 1 bit to
- RCR AX, 1 ; the right and accumulate sticky flag
- SHR DX, 1 ; shift DX:BX:AH
- RCR BX, 1 ; 1 bit to
- RCR AX, 1 ; the right and accumulate sticky flag
- ADD CL, 4 ; remaining bit shifts
- JZ $shft_done ; no shifts left
- $bit_shift: NEG AL ; sticky flag <> 0 ?
- SBB AL, AL ; set to FFh if not 0
-
- ALIGN 4
-
- $shift_loop: SHR DX, 1 ; shift DX:BX:AH
- RCR BX, 1 ; 1 bit to
- RCR AX, 1 ; the right and accumulate sticky flag
- INC CL ; adjust shift counter
- JNZ $shift_loop ; until counter zero
- $shft_done: NEG CH ; test if rounding flag set
- SBB CH, CH ; CH = FFh if rounding, CH = 0 if trunc
- AND AH, CH ; clear fraction part if trunc
- ADD AX, 8000h ; round up ? AH = guard, AL = sticky
- JNZ $round ; if no tie case (AH = 80, AL = 0)
- ROR BL, 1 ; move least significant
- ROL BL, 1 ; bit into carry
- $round: POP CX ; get original sign flag
- ADC BX, 0 ; round up
- ADC DX, 0 ; result if carry set
- XCHG AX, BX ; result in DX:AX
- OR CH, CH ; original argument negative ?
- JNS $pos_long ; no, was positive
- NOT DX ; negate
- NEG AX ; longint
- SBB DX, -1 ; in DX:AX
- JNC $rnd_done ; DX:AX = 0, no need to check for ovrfl.
- $pos_long: XOR CH, DH ; XOR sign of argument and sign of result
- ADD CH, CH ; CY, if signs differ (= overflow)
- $rnd_done: RET ; done
- RealTrunc ENDP
-
- ALIGN 4
-
- RTrunc PROC FAR
- XOR CH, CH ; flag truncation
- CALL RealTrunc ; convert real to longint
- JC RRangeError ; longint overflowed
- RET ; done
- RTrunc ENDP
-
- ALIGN 4
-
- RRound PROC FAR
- MOV CH, 1 ; flag rounding
- CALL RealTrunc ; convert real to longint
- JC RRangeError ; longint overflowed
- RET ; done
- RRound ENDP
-
- RRangeError: MOV AX, 0CFh ; error code 207 (invalid fp operation)
- JMP HaltError ; execute error handler
-
- ALIGN 4
-
- CODE ENDS
-
- END