0,0 → 1,237 |
;***************************************************************************** |
;* |
;* 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! |
;* |
;***************************************************************************** |
|
|
; double modf( double value, double *iptr ); |
; |
; Description: |
; The modf function breaks the argument value into integral and |
; fractional parts, each of which has the same sign as the argument. |
; It stores the integral part as a double in the object pointed to |
; by iptr. |
; |
; Returns: |
; The modf function returns the signed fractional part of value. |
; |
; 18-oct-86 ... Fraction in Modf not computed right |
; significant digits |
; |
include mdef.inc |
include struct.inc |
|
modstart amodf386 |
|
xdefp __ModF |
xdefp __ZBuf2F |
|
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] |
;[] |
;[] __ModF |
;[] |
;[] void __ModF( double near *AX, double near *DX ); |
;[] Input: EAX - pointer to double precision float |
;[] EDX - place to store integral part |
;[] Output: [EAX] - fractional part of value. |
;[] [EDX] - integral part of value |
;[] |
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] |
|
defpe __ModF |
push EBP ; save BP |
push ESI ; save SI |
push EDI ; save DI |
push ECX ; save CX |
push EBX ; save BX |
mov ESI,EDX ; get address for ipart |
mov EBP,EAX ; get address of float |
mov EAX,0[EBP] ; get float |
mov EDX,4[EBP] ; . . . |
xchg ESI,EBP ; flip pointers |
mov 0[EBP],EAX ; store integral part of value |
mov 4[EBP],EDX ; . . . |
_guess ; guess: fraction is zero |
mov ECX,EDX ; - get exponent |
and ECX,7FF00000h ; - get exponent part of R into DI |
je short done ; - set integer part to 0 if exponent = 0 |
cmp ECX,(3FFh+52) shl 20; - check for exponent > 52 |
_quif b ; - quit if fraction not zero |
xchg EBP,ESI ; - get address of fractional part |
done: sub EAX,EAX ; - set fraction(or integer) to 0 |
mov 4[EBP],EAX ; - . . . |
mov 0[EBP],EAX ; - . . . |
pop EBX ; - restore BX |
pop ECX ; - restore CX |
pop EDI ; - restore DI |
pop ESI ; - restore SI |
pop EBP ; - restore BP |
ret ; - return |
_endguess ; endguess |
mov EDI,ECX ; save exponent |
shr ECX,20 ; move exponent to bottom |
sub CX,03FFh ; remove bias |
jb done ; quit if number < 1.0 |
push EDX ; save sign |
sub EAX,EAX ; initialize mask to 0 |
mov EDX,0FFF00000h ; ... |
cmp CL,20 ; if exponent > 20 |
_if a ; then |
sar EDX,21 ; - set ESI to all ones |
rcr EAX,1 ; - set high bit of EBX |
sub CL,21 ; - get shift count for second part |
sar EAX,CL ; - create rest of mask |
_else ; else |
sar EDX,CL ; - create mask in high part only |
_endif ; endif |
and 4[EBP],EDX ; mask off the remaining fraction bits |
and 0[EBP],EAX ; . . . |
not EDX ; complement the mask to get fractional part |
not EAX ; . . . |
mov EBP,ESI ; get address of fractional part |
and EDX,4[EBP] ; get fraction bits |
and EAX,0[EBP] ; . . . |
call Norm ; normalize the fraction |
pop ESI ; restore sign |
or EDX,EDX ; if fraction is not 0 |
_if ne ; then |
and ESI,80000000h ; - isolate sign |
or EDX,ESI ; - set sign in fractional part |
_endif ; endif |
mov 4[EBP],EDX ; store fractional part |
mov 0[EBP],EAX ; . . . |
pop EBX ; restore BX |
pop ECX ; restore CX |
pop EDI ; restore DI |
pop ESI ; restore SI |
pop EBP ; restore BP |
ret ; return |
endproc __ModF |
|
|
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> |
;<> <> |
;<> __ZBuf2F - convert buffer of significant digits into floating <> |
;<> void __ZBuf2F( char near *buf, double near *value ) <> |
;<> <> |
;<> input: EAX - address of buffer of significant digits <> |
;<> EDX - place to store value <> |
;<> output: [EDX] - floating point number <> |
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> |
|
defpe __ZBuf2F |
push EBP ; save BP |
push ESI ; save SI |
push EDI ; save DI |
push ECX ; save CX |
push EBX ; save BX |
push EDX ; save pointer to result |
mov ESI,EAX ; get address of buffer |
sub EDX,EDX ; set 54-bit integer to 0 |
sub ECX,ECX ; . . . |
sub EAX,EAX ; zero out EAX |
_loop ; loop (convert digits into 54-bit int) |
mov AL,[ESI] ; - get next digit |
cmp AL,0 ; - quit if at end of buffer |
_quif e ; - . . . |
|
;[] multiply current value in EDX:ECX by 10 |
|
mov EDI,EDX ; - save current value |
mov EBX,ECX ; - ... |
_shl ECX,1 ; - multiply number by 4 |
_rcl EDX,1 ; - by shifting left 2 places |
_shl ECX,1 ; - . . . |
_rcl EDX,1 ; - . . . |
add ECX,EBX ; - add original value |
adc EDX,EDI ; - (this will make it times 5) |
_shl ECX,1 ; - shift left to make it times 10 |
_rcl EDX,1 ; - . . . |
and AL,0Fh ; - isolate binary digit |
add ECX,EAX ; - add in current digit |
adc EDX,0 ; - . . . |
inc ESI ; - point to next digit in buffer |
_endloop ; endloop |
mov EAX,ECX ; get low order word into EAX |
|
;[] Turn the integer in EDX:EAX into a real number |
|
mov EDI,(3FFh+52) shl 20; set exponent |
call Norm ; convert the 52 bit integer to a float |
pop EBP ; restore pointer to result |
mov 4[EBP],EDX ; store result |
mov 0[EBP],EAX ; . . . |
pop EBX ; restore BX |
pop ECX ; restore CX |
pop EDI ; restore DI |
pop ESI ; restore SI |
pop EBP ; restore BP |
ret ; return to caller |
endproc __ZBuf2F |
|
|
;[] Norm normalizes an unsigned real in EDX:EAX |
;[] expects the exponent to be in EDI. The real returned is in 'packed' |
;[] format |
;[] ESI is destroyed |
|
Norm proc near ; normalize floating point number |
sub ESI,ESI ; clear out SI |
or ESI,EAX ; see if the integer is zero |
or ESI,EDX ; . . . |
je short Z_52ret ; if integer is zero, return to caller |
test EDX,0FFF00000h ; see if we have to shift forward or backward |
_if e ; if (we haven't shifted msb into bit 53) |
_loop ; - loop |
sub EDI,00100000h ; - - exp <-- exp - 1 |
_shl EAX,1 ; - - shift integer left by 1 bit |
_rcl EDX,1 ; - - . . . |
test EDX,0FFF00000h; |
_until ne ; - until( msb is shifted into bit 53 ) |
_else ; else (we must shift to the right) |
test EDX,0FFE00000h ; - |
je short done1 ; - if msb is bit 53, we are done |
_loop ; - loop |
add EDI,00100000h ; - - exp <-- exp + 1 |
shr EDX,1 ; - - shift integer right by 1 bit |
rcr EAX,1 ; - - . . . |
rcr ESI,1 ; - - save lsb |
test EDX,0FFE00000h; - |
_until e ; - until( msb is bit 53 ) |
_rcl ESI,1 ; - get lsb |
adc EAX,0 ; - and use it to round off the number |
adc EDX,0 ; - . . . |
_endif ; endif |
done1: and EDX,000FFFFFh ; clear out implied bit |
or EDX,EDI ; put in exponent |
Z_52ret:ret ; return |
endproc Norm |
|
endmod |
end |