386fprem.inc
来自「开放源码的编译器open watcom 1.6.0版的源代码」· INC 代码 · 共 178 行
INC
178 行
;*****************************************************************************
;*
;* Open Watcom Project
;*
;* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;* ========================================================================
;*
;* This file contains Original Code and/or Modifications of Original
;* Code as defined in and that are subject to the Sybase Open Watcom
;* Public License version 1.0 (the 'License'). You may not use this file
;* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;* provided with the Original Code and Modifications, and is also
;* available at www.sybase.com/developer/opensource.
;*
;* The Original Code and all software distributed under the License are
;* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;* NON-INFRINGEMENT. Please see the License for the specific language
;* governing rights and limitations under the License.
;*
;* ========================================================================
;*
;* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
;* DESCRIBE IT HERE!
;*
;*****************************************************************************
xdefp __fprem
xdefp ___fprem
; EDX:EAX ECX:EBX
; double fprem( double x, double modulus, int *quot )
; int fprem( long double *x, long double *modulus )
; EAX EDX
;
defp __fprem
_guess ; guess: number is 0
cmp word ptr 8[EAX],0; - quit if not 0
_quif ne ; - ...
cmp dword ptr 4[EAX],0; - quit if not 0
_quif ne ; - ...
cmp dword ptr [EAX],0; - quit if not 0
_quif ne ; - ...
sub EAX,EAX ; - integer quotient is 0
ret ; - return
_endguess ; endguess
_guess ; guess: modulus is 0
cmp word ptr 8[EDX],0; - quit if not 0
_quif ne ; - ...
cmp dword ptr 4[EDX],0; - quit if not 0
_quif ne ; - ...
cmp dword ptr [EDX],0; - quit if not 0
_quif ne ; - ...
sub EDX,EDX ; - set result to 0
mov [EAX],EDX ; - ...
mov 4[EAX],EDX ; - ...
mov 8[EAX],DX ; - ...
sub EAX,EAX ; - integer quotient is 0
ret ; - return
_endguess ; endguess
push EBP ; save EBP
push ESI ; save ESI
push EDI ; save EDI
push EDX ; save EDX
push ECX ; save ECX
push EBX ; save EBX
push EAX ; save address of operand
mov SI,8[EAX] ; get exponent of op1
mov DI,8[EDX] ; get exponent of op2
mov ECX,4[EDX] ; get modulus
mov EBX,[EDX] ; ...
mov EDX,4[EAX] ; get operand
mov EAX,[EAX] ; ...
call ___fprem ; calc remainder
pop ECX ; restore address of operand
mov [ECX],EAX ; store the remainder
mov 4[ECX],EDX ; ...
mov 8[ECX],SI ; ...
mov EAX,EDI ; store quotient
pop EBX ; restore EBX
pop ECX ; restore ECX
pop EDX ; restore EDX
pop EDI ; restore EDI
pop ESI ; restore ESI
pop EBP ; restore EBP
ret ; return
endproc __fprem
defp ___fprem
push ESI ; save sign of operand
push EDI ; save high part of modulus
and ESI,00007FFFh ; isolate exponent
and EDI,00007FFFh ; isolate exponent of modulus
sub ESI,EDI ; calculate difference in exponents
_if ge ; if operand >= modulus
sub EDI,EDI ; - set quotient to 0
_loop ; - loop
_guess ; - - guess
cmp ECX,EDX ; - - - The purpose of this guess is to
_quif ne ; - - - determine if the divisor will subtract
cmp EBX,EAX ; - - -
je try ; - - -
_endguess ; - - endguess
_if c ; - - if the carry is set (ie the modulus will
; - - - definitely subtract from the dividend
; - - - without a borrow
try:
sub EAX,EBX ; - - - subtract divisor from dividend
sbb EDX,ECX ; - - - . . .
stc ; - - - set carry to indicate that modulus was
; - - - successfully subtracted from dividend
_endif ; - - endif
didnt_go: _rcl EDI,1 ; - - rotate 1 (if carry set) into quotient word
dec ESI ; - - adjust difference in exponents
jl _done ; - - quit if done
_shl EAX,1 ; - - shift dividend left
_rcl EDX,1 ; - - . . .
jc try
;<> If bit 5 of dividend is set here, we didnt subtract the modulus from the
;<> dividend (recall that the divisor has a 1 in the msb -- if we subtracted
;<> it from the dividend without a borrow, the dividend would not have a one
;<> in its msb to be shifted into bit 5 tested for in the condition above. If
;<> we are rotating a bit into bit 5, the dividend is now big enough that we
;<> can be sure of subtracting out the divisor without a borrow, as we have
;<> shifted it left one digit.
or EDX,EDX ; - - check top bit of dividend
_until ns ; - until
jmp short didnt_go ; - continue
_done: sub ESI,ESI ; - set ESI to 0
; normalize the remainder in AL:BX:CX:DX
_guess ; - guess: number is zero
or EAX,EAX ; - - quit if not zero
_quif ne ; - - ...
or EDX,EDX ; - - ...
_quif ne ; - - ...
_admit ; - admit: not zero
_loop ; - - loop
or EDX,EDX ; - - - quit if number is normalized
_quif s ; - - - . . .
_rcl EAX,1 ; - - - shift result left
_rcl EDX,1 ; - - - ...
dec ESI ; - - - decrement exponent
_endloop ; - - endloop
pop ECX ; - - get high part of modulus
push ECX ; - - save it again
and ECX,00007FFFh ; - - isolate exponent of modulus
add ESI,ECX ; - - adjust exponent of result
_endguess ; - endguess
_else ; else
add ESI,EDI ; - restore exponent
sub EDI,EDI ; - set quotient to 0
_endif ; endif
pop ECX ; restore high part of modulus
pop EBX ; restore sign
and EBX,00008000h ; isolate sign bit
or ESI,EBX ; merge sign with exponent
or EDX,EDX ; test high word of remainder
_if e ; if remainder is zero
sub ESI,ESI ; - clear the sign and exponent
_endif ; endif
xor BX,CX ; calc sign of quotient
_if s ; if quotient should be negative
neg EDI ; - negate quotient
_endif ; endif
ret ; return
endproc ___fprem
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?