Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
kccdist/lib/math/modf.c
There are 8 other files named modf.c in the archive. Click here to see a list.
/*
* MODF.C - split floating point number into int and fractional parts
*
* This code does NOT conform to the description of the modf function
* as defined in Harbison and Steele's "C: A Reference Manual",
* section 11.3.18. We believe that H&S is wrong in saying that the
* 2nd arg to "modf" is an (int *); both ANSI and BSD say it is a
* (double *), which moreover makes more sense. Otherwise the
* description is accurate.
*
* For the DECSYSTEM-20 the double precision word format is:
*
* WORD N => SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMMMMM
* WORD N+1 => XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
*/
#include "c-env.h" /* So can see what format we're using */
#define SIGN_MASK 0400000000000 /* Mask for sign bit */
#define EXP_MASK 0377000000000 /* Mask for exponent */
#define MANT_MASK 0400777777777 /* Mask for mantissa */
#define LEXP_MASK 0377 /* Mask for shifted exponent */
#define EXP_SHIFTS 27 /* Shifts for exp in LSBs */
double
modf(x, iptr)
double x, *iptr; /* Note 2nd arg is ptr to double, not int! */
{
#if 0
/*
* note that this code is buggy in that there is no such thing as
* a long int on this machine (i assumed it was a double-word int);
* so the shifting operations are single-word, and all 2nd word
* precision is flushed! lose lose
*/
int exp, *vptr, negative = 0;
long int *y;
double z;
vptr = (int *) &x; /* point to first word of double */
exp = ((unsigned) (*vptr & EXP_MASK) >> EXP_SHIFTS); /* extract exp */
if (x < 0) { /* if negative number, exponent is */
exp = ~exp & LEXP_MASK; /* stored as 1's complement, so fix */
negative = 1; /* flag to save double comparisons */
}
exp -= 128; /* make it signed, not excess-128 */
if (exp <= 0) { /* mant * 2^0 is less than 1 */
*nptr = 0; /* so return 0 as integer part */
return x; /* and original number as fraction */
}
else {
z = x; /* copy this so we don't lose bits */
if (negative) /* if negative number, mantissa */
*vptr = -*vptr; /* is 2's complement too */
*vptr &= MANT_MASK; /* nuke old exponent to 0 */
y = (long int *) &x; /* point to double-word x */
(unsigned) *y >>= (EXP_SHIFTS - exp); /* >> mant to make int */
*nptr = (negative) ? -*vptr : *vptr; /* 1st word is int part */
x = z; /* get back x */
*y <<= exp; /* shift remaining bits to */
*vptr &= (MANT_MASK ^ SIGN_MASK); /* decimal-point position */
if (negative && *vptr != 0)
*vptr |= (~128 & LEXP_MASK) << EXP_SHIFTS | SIGN_MASK;
else
*vptr |= (128 << EXP_SHIFTS); /* stick in new exp */
return x += 0.0; /* normalize and return result */
}
/* End of commented-out stuff */
#elif CENV_DFL_H /* PDP-10 hardware double prec fmt, only */
#asm
EXTERN $ZERO /* From CRT */
DMOVE 1,-2(17) ; Get double arg
SKIPGE 7,1 ; Check for negative number, remember sign in 7
DMOVN 1,1 ; Negative, so turn it over
CAMGE 1,[201000,,0] ; Do we have an integer part?
JRST [ SETZB @-3(17) ; No, set integer part to (double) 0
CAIG 7,0 ; If arg was negative,
DMOVN 1,1 ; must return negative result.
POPJ 17,]
; Have an integer part. Find mask to flush fraction bits.
LDB 4,[331000,,1] ; Get exponent
MOVNI 4,-200(4) ; Find -<# bits in integral part>
MOVSI 5,400000 ; Get a sign-bit-set doubleword mask
SETZ 6,
ASHC 5,-10(4) ; Shift mask over exponent & integer bits
DMOVE 3,1 ; Copy positive # for integer part
AND 3,5
AND 4,6 ; Mask out fraction bits, leave integer bits
TLZ 5,777000 ; After ensuring that exponent preserved,
ANDCM 1,5 ; apply reverse mask to get fraction bits.
ANDCM 2,6
JUMPL 7,[ ; If negation needed,
DMOVNM 3,@-3(17) ; store negated integer part
DMOVN 1,1 ; and negate returned fractional part
JRST .+2] ; Skip over DMOVEM
DMOVEM 3,@-3(17) ; Store integer part
DFAD 1,$ZERO ; and normalize returned fraction.
; Drop thru to return
#endasm
#elif 0 /* Should be ELSE */
#error modf() not implemented for this CPU.
#endif
}