/* Copyright (c)1994-2000 Begemot Computer Associates. All rights reserved.
 * See the file COPYRIGHT for details of redistribution and use. */
/* $Id: float.h 510 2006-10-26 14:18:49Z brandt_h $ */

# ifdef FLOAT_I386

/*
 * i386 floating point operations
 *
 * there is a problem with bsdi 1.0 here, because on signaling the systems
 * reset the 387 control word to default (53 bit).
 * so we set before each operation the control word and hope we will not
 * be interrupted (block all signals each time isn't a good idea, I think)
 *
 */

const short initfpmem = 0xf37;

# define InitFp()	/* sigprocmask(block all signals) */ \
			asm("fldcw %0" :: "m" (initfpmem));
# define EndFp()	/* sigprocmask(enable all signals) */

/* 
 * add S to A
 * sub S from A
 * mul A by S
 * divide A by S (S is already checked for 0)
 * the limits of the host float should be sufficient not
 * to produce any errors.
 */
# define AddF(A,S)	asm("fldt %2; fldt %0; faddp; fstpt %0; fwait"	\
				: "=m"(A) : "0"(A), "m"(S))
# define SubF(A,S)	asm("fldt %2; fldt %0; fsubp; fstpt %0; fwait"	\
				: "=m"(A) : "0"(A), "m"(S))
# define MulF(A,S)	asm("fldt %2; fldt %0; fmulp; fstpt %0; fwait"	\
				: "=m"(A) : "0"(A), "m"(S))
# define DivF(A,S)	asm("fldt %2; fldt %0; fdivp; fstpt %0; fwait"	\
				: "=m"(A) : "0"(A), "m"(S))

/*
 * separate A in fractional part F and integral part I
 */
# define ModF(A,F,I)	asm("fldt %2; frndint; fstpt %1; \
			     fldt %1; fldt %2; fsubp; fstpt %0; fwait" \
				: "=m"(F), "=m"(I) : "m"(A))
/*
 * check if S is zero
 */
# define IsZ(S)		({int _r; asm("fldt %1; fldz; fucompp; fnstsw %0; fwait" \
				: "=a"(_r) : "m"(S)); \
			  (_r & 0x4500) == 0x4000;})

/*
 * check if S is negativ
 */
# define IsN(S)		((S).s)


/*
 * convert long to float
 */
# define CnvL(A,L)	asm("pushl %1; fildl (%%esp); add $4,%%esp; fstpt %0; fwait" \
				: "=m"(A) : "g"(L))

/*
 * chop float to long, range already checked
 * chop already set by InitFp
 * &L makes sure L doesn't go into a register
 */
# define CnvF2L(S,L)	asm("fldt %1; fistpl %0; fwait" \
				: "=m"(L) : "m"(S), "r"(&(L)));


/*
 * return K so that 2^K <= A < 2^(K+1)
 * (A may not be 0 here)
 */
# define FrExp(A)	((signed)(A).e - EXP_OFF)



/*
 * i386 temporary float format
 */
struct ifloat {
	u_int		ml : 32;	/* low mant */
	u_int		mh : 32;	/* high mant, high bit is 1 */
	u_int		e : 15;		/* expo offset 0x3fff */
	u_int		s : 1;		/* sign */
};
# define EXP_OFF	0x3fff

/*
 * We may need this aligned. Assume worst case is 16.
 */
static struct ifloat	host_null ALIGNED(16);


/*
 * return i386 temp float mantissa as 64 bit fixed point value with
 * point right after the most significant bit and 1.0 > m >= 0.5
 */
# define GetMant(P)	((((u_xquad_t)(P)->mh & 0x7FFFFFFF) << 32) | (u_xquad_t)(P)->ml)
# define GetExp(P)	((int)(signed short)(P)->e - EXP_OFF + 1)
# define GetSign(P)	(P)->s

/*
 * rebuild i386 temp float
 */
# define SetMant(H,M)	(((H)->mh = ((M) >> 32) | 0x80000000U), (H)->ml = (M))
# define SetExp(H,E)	((H)->e = (E) - 1 + EXP_OFF)
# define SetSign(H,S)	((H)->s = (S))



/*
 * covert internal float to double, just for printing and debuging
 */
static double
mkd(struct ifloat *f)
{
	static double	dd;

	asm("fldt %1 ; fstpl %0 ; fwait" : "=m"(dd) : "m"(*f));
	return dd;
	printf("%.16e", dd);
}


/*
 * convert pdp float to double for printing
 * precision may be lost and over/underflow may occure
 */
static double
mkdouble(pdp_float_t *f, int d)
{
	struct ifloat h;

	unfold(f, &h, d);
	return mkd(&h);
}


/*
 * dump an i386 temp float
 */
static void
dmpflt(struct ifloat *f)
{
	int e = f->e - EXP_OFF;

	printf("%c ", "+-"[f->s]);
	if(f->e)
		printf(" %04x ", e & 0x7fff);
	else 
		printf("    0 ");	
	printf("%08x %08x", f->mh, f->ml);
}

# endif
# if defined(FLOAT_SPARC) || defined(FLOAT_QLIB)

/*
 * sparc floating point operations for compilers that don't know extended float
 * implemented in as because gcc doesn't know about extended doubles
 *
 * See the SPARC Architecture Manual, Version 8, page 238, for further
 * information on Quad Precision Floating Point.
 */

/*
 * sparc quad float format, usually emulated
 */
struct struct ifloat {
	u_int		s : 1;		/* sign bit */
	u_int		e : 15;		/* expo offset 0x3fff */
	u_int		m0 : 16;	/* mantissa 112 bit */
	u_int		m1 : 32;
	u_int		m2 : 32;
	u_int		m3 : 32;
};
# define EXP_OFF	0x3fff

/*
 * We may need this aligned. Assume worst case is 16.
 */
static struct ifloat		host_null ALIGNED(16);

# define InitFp()
# define EndFp()

/* 
 * add S to A
 * sub S from A
 * mul A by S
 * divide A by S (S is already checked for 0)
 * the limits of the host float should be sufficient not
 * to produce any errors.
 */
# ifdef FLOAT_SPARC
# define AddF(A,S)	asm("	ldd	[%1], %%f0		;\
				ldd	[%1 + 0x8], %%f2	;\
				ldd	[%0], %%f4		;\
				ldd	[%0 + 0x8], %%f6	;\
				faddq	%%f0, %%f4, %%f4	;\
				std	%%f6, [%0 + 0x8]	;\
				std	%%f4, [%0]		\
				" : : "r"(&A), "r"(&S) : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7")

# define SubF(A,S)	asm("	ldd	[%1], %%f0		;\
				ldd	[%1 + 0x8], %%f2	;\
				ldd	[%0], %%f4		;\
				ldd	[%0 + 0x8], %%f6	;\
				fsubq	%%f4, %%f0, %%f4	;\
				std	%%f6, [%0 + 0x8]	;\
				std	%%f4, [%0]		\
				" : : "r"(&A), "r"(&S) : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7")
# define MulF(A,S)	asm("	ldd	[%1], %%f0		;\
				ldd	[%1 + 0x8], %%f2	;\
				ldd	[%0], %%f4		;\
				ldd	[%0 + 0x8], %%f6	;\
				fmulq	%%f4, %%f0, %%f4	;\
				std	%%f6, [%0 + 0x8]	;\
				std	%%f4, [%0]		\
				" : : "r"(&A), "r"(&S) : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7")
# define DivF(A,S)	asm("	ldd	[%1], %%f0		;\
				ldd	[%1 + 0x8], %%f2	;\
				ldd	[%0], %%f4		;\
				ldd	[%0 + 0x8], %%f6	;\
				fdivq	%%f4, %%f0, %%f4	;\
				std	%%f6, [%0 + 0x8]	;\
				std	%%f4, [%0]		\
				" : : "r"(&A), "r"(&S) : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7")

/*
 * separate A in fractional part F and integral part I
 * this version breaks on big floats
 */
# define ModF(A,F,I)	asm("	ldd	[%0], %%f0		;\
				ldd	[%0+0x8], %%f2		;\
				fqtoi	%%f0, %%f4		;\
				fitoq	%%f4, %%f4		;\
				std	%%f6, [%2 + 0x8]	;\
				std	%%f4, [%2]		;\
				fsubq	%%f0, %%f4, %%f4	;\
				std	%%f6, [%1 + 0x8]	;\
				std	%%f4, [%1]		\
				" :: "r"(&A), "r"(&F),  "r"(&I) : "l0", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7")

/*
 * check if S is zero
 */
# define IsZ(S)		({ int _r;				;\
			asm("	ldd	[%1], %%f0		;\
				ldd	[%1+0x8], %%f2		;\
				ldd	[%2], %%f4		;\
				ldd	[%2+0x8], %%f6		;\
				fcmpq	%%f0, %%f4		;\
				nop				;\
				fbe,a	1f			;\
				mov	1,%0			;\
				mov	0,%0			;\
			1:					;\
				" : "=r"(_r) : "r"(&S), "r"(&host_null) : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7"); \
			_r; })

/*
 * check if S is negativ
 */
# define IsN(S)			((S).s)


/*
 * convert long to float
 */
# define CnvL(A,L)	asm("	ld	[%1], %%f0		;\
				fitoq	%%f0, %%f0		;\
				std	%%f2, [%0 + 0x8]	;\
				std	%%f0, [%0]		\
				" : : "r"(&A), "r"(&L) : "f0", "f1", "f2", "f3")

/*
 * chop float to long, range already checked
 * chop already set by InitFp
 */
# define CnvF2L(S,L)	asm("	ldd	[%1], %%f0		;\
				ldd	[%1+0x8], %%f2		;\
				fqtoi	%%f0, %0		\
				" : "=f"(L) : "r"(&S) : "f0", "f1", "f2", "f3")

# endif
# ifdef FLOAT_QLIB

struct ifloat	_Q_add(struct ifloat, struct ifloat);
struct ifloat	_Q_sub(struct ifloat, struct ifloat);
struct ifloat	_Q_mul(struct ifloat, struct ifloat);
struct ifloat	_Q_div(struct ifloat, struct ifloat);
int		_Q_qtoi(struct ifloat);
double		_Q_qtod(struct ifloat);
struct ifloat	_Q_itoq(int);
int		_Q_feq(struct ifloat, struct ifloat);
int		_Q_fgt(struct ifloat, struct ifloat);
int		_Q_fge(struct ifloat, struct ifloat);

struct ifloat 	modq(struct ifloat, struct ifloat *);

# define AddF(A,S)	(A) = _Q_add((A), (S))
# define SubF(A,S)	(A) = _Q_sub((A), (S))
# define MulF(A,S)	(A) = _Q_mul((A), (S))
# define DivF(A,S)	(A) = _Q_div((A), (S))
# define ModF(A,F,I)	(F) = modq((A), &(I))
# define IsZ(A)		_Q_feq((A), host_null)
# define IsN(S)		((S).s)
# define CnvL(A,L)	(A) = _Q_itoq((L))
# define CnvF2L(S,L)	(L) = _Q_qtoi((S))

# endif


/*
 * return K so that 2^K <= A < 2^(K+1)
 * (A may not be 0 here)
 */
# define FrExp(A)	((signed)(A).e - EXP_OFF)


/*
 * return sparc float mantissa as a 64bit fixed point value with
 * point after the 1st bit to the left and 1.0 > m >= 0.5
 */
# define GetMant(P)	(((u_xquad_t)(P)->m0 << 47) |		\
			 ((u_xquad_t)(P)->m1 << 15) |		\
			 ((u_xquad_t)(P)->m2 >> 17))
# define GetExp(P)	((int)(signed short)(P)->e - EXP_OFF + 1)
# define GetSign(P)	(P)->s


/*
 * insert mantissa into sparc float
 */
# define SetMant(H,M)	(((H)->m0 = (M) >> 47), ((H)->m1 = (M) >> 15),	\
			 ((H)->m2 = (M) << 17), ((H)->m3 = 0))
# define SetExp(H,E)	((H)->e = (E) - 1 + EXP_OFF)
# define SetSign(H,S)	((H)->s = (S))


/*
 * covert extended float to double, just for printing and debuging
 */
static double
mkd(ifloat *f)
{
# ifdef FLOAT_SPARC
	static double	dd;

	asm("   ldd     [%1], %%f0              ;\
		ldd     [%1 + 0x8], %%f2        ;\
		fqtod	%%f0, %0"
	  : "=f"(dd) : "r"(f) : "f0", "f1", "f2", "f3");
	return dd;
# endif
# ifdef FLOAT_QLIB
	return _Q_qtod(*f);
# endif
}


/*
 * dump a float
 */
static void
dmpflt(ifloat *f)
{
	int e = f->e - EXP_OFF;

	printf("%c ", "+-"[f->s]);
	if(f->e)
		printf(" %04x ", e & 0x7fff);
	else 
		printf("    0 ");	
	printf("%04x %08x %08x %08x", f->m0, f->m1, f->m2, f->m3);
}


/*
 * convert pdp float to double for printing
 * precision may be lost and over/underflow may occure
 */
static double
mkdouble(pdp_float_t *f, int d)
{
	struct ifloat h;

	unfold(f, &h, d);
	return mkd(&h);
}


# ifdef FLOAT_QLIB
struct ifloat
modq(struct ifloat val, struct ifloat *iptr)
{
	static ifloat maxp2 = { 0, 112+0x3FFF, 0, 0, 0, 0 };
	static ifloat c1 = { 0, 0x3FFF, 0, 0, 0, 0 };
	struct ifloat aval = val;

	aval.s = 0;
	if(_Q_fge(aval, maxp2))
		*iptr = val;
	else {
		*iptr = _Q_add(aval, maxp2);
		*iptr = _Q_sub(*iptr, maxp2);
		while(_Q_fgt(*iptr, aval))
			*iptr = _Q_sub(*iptr, c1);
		if(val.s)
			iptr->s = 1;
	}
	return _Q_sub(val, *iptr);
}
# endif
# endif

# ifdef FLOAT_GENERIC


# include <math.h>

# define InitFp()		/* nothing to do */
# define EndFp()		/* nothing to do */

/*
 * 'generic' floating point
 * this format is reasonable near the pdp format, but:
 *   1.0 <= m < 2.0
 *   mantissa has 63 bits and has point after two msb
 *   exponent has more bits and offset of 0x3FFF
 * your compiler must have 64 bit signed and unsigned arithmetic (u_xquad_t, signed quad_t)
 */
struct ifloat {
	int		s;	/* sign: 1 means neg */
	u_int		e;	/* exponent with offset 0x3FFF, 0 for real 0 */
	u_xquad_t 	m;	/* mantissa is 1.0 <= m < 2.0 or m == 0 */
};
# define EOFFS	0x3FFF
# define MBITS	63

/*
 * We may need this aligned. Assume worst case is 16.
 */
static struct ifloat	host_null ALIGNED(16);

# define AddF(A,S)	(void)((A) = F_add((A), (S)))
# define SubF(A,S)	(void)((A) = F_sub((A), (S)))
# define MulF(A,S)	(void)((A) = F_mul((A), (S)))
# define DivF(A,S)	(void)((A) = F_div((A), (S)))
# define ModF(A,F,I)	(void)((F) = F_mod((A), &(I)))
# define IsZ(A)		((A).e == 0)
# define IsN(A)		((A).s)
# define CnvL(A,L)	(void)((A) = F_int((L)))
# define CnvF2L(S,L)	(void)((L) = F_chop((S)))

# define FrExp(A)	((signed)(A).e - EOFFS)

# define GetMant(P)	(((P)->m & ~f_msb) << 1)
# define GetExp(P)	((int)(P)->e - EOFFS + 1)
# define GetSign(P)	((P)->s)

# define SetMant(H,M)	(void)((H)->m = ((M) >> 1) | f_msb)
# define SetExp(H,E)	(void)((H)->e = (E) - 1 + EOFFS)
# define SetSign(H,S)	(void)((H)->s = (S))

struct ifloat	F_add(struct ifloat a, struct ifloat b);
struct ifloat	F_sub(struct ifloat a, struct ifloat b);
struct ifloat	F_mul(struct ifloat a, struct ifloat b);
struct ifloat	F_div(struct ifloat a, struct ifloat b);
struct ifloat	F_mod(struct ifloat a, struct ifloat *ip);
int	F_cmp(struct ifloat a, struct ifloat b);
long	F_chop(struct ifloat a);
long	F_round(struct ifloat a);
struct ifloat	F_int(long);

typedef double ldouble;		/* should be long double */
# define XFREXP	frexp
# define XLDEXP	ldexp

struct ifloat 	F_quad(ldouble ld);
ldouble	F_double(struct ifloat a);

char *	F_dump(struct ifloat a);

static void		f_add(struct ifloat *a, struct ifloat *b, struct ifloat *c);
static void		f_sub(struct ifloat *a, struct ifloat *b, struct ifloat *c);
static void		f_norm(struct ifloat *a);
static const u_xquad_t	f_msb = (u_xquad_t)1 << 62;
static const u_xquad_t	f_carry = (u_xquad_t)1 << 63;
static const struct ifloat	f_null = {0, 0, 0};

/*
 * debugging
 */
static double
mkdouble(pdp_float_t *a, int d) 
{
	struct ifloat h;

	unfold(a, &h, d);
	return (double)F_double(h);
}

static double
mkd(struct ifloat *f)
{
	return (double)F_double(*f);
}

static void
dmpflt(struct ifloat *f)
{
	printf("%s", F_dump(*f));
}

/*
 * make (long)double from struct ifloat
 */
ldouble
F_double(struct ifloat a)
{
	ldouble	v;
	ldouble p;
	int i;
	u_xquad_t mask;

	if(a.e == 0)
		return 0;
	v = 0.0;
	for(i = 0, p = 1.0, mask = f_msb; i < MBITS; i++, mask >>= 1, p /= 2)
		if((a.m & mask) != 0)
			v += p;

	return a.s ? -XLDEXP(v, (int)a.e - EOFFS) : XLDEXP(v, (int)a.e - EOFFS);
}

/*
 * make float from (long)double
 * sorry, there is no frmant function in analogy to frexp so we
 * must get the mantissa bitwise
 */
struct ifloat
F_quad(ldouble ld)
{
	int i;
	u_xquad_t mask;
	struct ifloat a;

	if(ld == 0)
		return f_null;
	if(ld < 0) {
		a.s = 1;
		ld = -ld;
	} else
		a.s = 0;
	ld = 2 * XFREXP(ld, &i);	/* ld now >= 1.0 && < 2.0 */
	a.e = i - 1 + EOFFS;
	a.m = 0;
	for(i = 0, mask = f_msb; i < MBITS; i++, mask >>= 1, ld *= 2)
		if(ld >= 1.0) {
			a.m |= mask;
			ld -= 1.0;
		}
	return a;
}

/*
 * dump a float
 */
char *
F_dump(struct ifloat a)
{
	static char buf[30];

	sprintf(buf, "%d %04x %08lx %08lx", a.s, a.e, (u_long)(a.m >> 32), (u_long)a.m);
	return buf;
}

/*
 * convert long to float
 */
struct ifloat
F_int(long v)
{
	struct ifloat c;

	if(v == 0)
		return f_null;
	c.s = (v < 0);
	c.e = EOFFS + MBITS - 1;
	if(v < 0)
		c.m = (u_xquad_t)-(xquad_t)v;
	else
		c.m = (u_xquad_t)v;
	f_norm(&c);
	return c;
}


/*
 * chop struct ifloat to long
 */
long
F_chop(struct ifloat a)
{
	int e;

	if(a.e == 0)
		return 0;
	if((e = (int)a.e - EOFFS) >= 32)
		return a.s ? 0x80000000U : 0x7fffffff;
	a.m >>= MBITS - 1 - e;
	if(!a.s) {
		if(a.m >= (u_xquad_t)0x80000000U)
			return 0x7fffffffU;
		return (long)a.m;
	} else {
		if(a.m >= (u_xquad_t)0x80000000U)
			return 0x80000000;
		return -(long)a.m;
	}
}

/*
 * round struct ifloat to long
 */
long
F_round(struct ifloat a)
{
	int e, r;

	if(a.e == 0)
		return 0;
	if((e = (int)a.e - EOFFS) >= 32)
		return a.s ? 0x80000000U : 0x7fffffff;
	a.m >>= MBITS - 1 - e - 1;
	r = (int)a.m & 1;
	a.m >>= 1;
	if(r)
		a.m += 1;
	if(!a.s) {
		if(a.m >= (u_xquad_t)0x80000000U)
			return 0x7fffffffU;
		return (long)a.m;
	} else {
		if(a.m >= (u_xquad_t)0x80000000U)
			return 0x80000000;
		return -(long)a.m;
	}
}

/*
 * add two floats
 */
struct ifloat
F_add(struct ifloat a, struct ifloat b)
{
	struct ifloat c;

	if(a.s == b.s)
		f_add(&a, &b, &c);
	else
		f_sub(&a, &b, &c);

	return c;
}

struct ifloat
F_sub(struct ifloat a, struct ifloat b)
{
	struct ifloat c;

	b.s = 1 - b.s;
	if(a.s == b.s)
		f_add(&a, &b, &c);
	else
		f_sub(&a, &b, &c);

	return c;
}

/*
 * multiply a and b
 */
struct ifloat
F_mul(struct ifloat a, struct ifloat b)
{
	struct ifloat	c;
	u_xquad_t	mask;
	int	i;

	/*
	 * multiplying with 0 gives 0
	 */
	if(a.e == 0 || b.e == 0)
		return f_null;

	/*
	 * sign and exponent are really simple
	 */
	c.s = a.s ^ b.s;
	c.e = (int)a.e - EOFFS + (int)b.e;

	c.m = 0;
	for(i = 0, mask = (u_xquad_t)1; i < MBITS; i++, mask <<= 1) {
		c.m >>= 1;
		if((a.m & mask) != 0)
			c.m += b.m;
	}
	if((c.m & f_carry) != 0) {
		c.e++;
		c.m >>= 1;
	}
	return c;
}


/*
 * compute a/b
 * note: if a or b is 0 then 0 is returned
 */
struct ifloat
F_div(struct ifloat a, struct ifloat b)
{
	struct ifloat c;
	int i;

	/*
	 * look for simple and bad cases
 	 */
	if(a.e == 0 || b.e == 0)		/* what else can we do? */
		return f_null;

	/*
	 * sign is easy, exponent can drop to low
	 */
	c.s = a.s ^ b.s;
	if((int)(c.e = (int)a.e - ((int)b.e - EOFFS)) <= 0)
		return f_null;

	/*
	 * we generate 1 bit more and shift back later if we get carry
	 * this is for cases like 1.000/1.FFF where we otherwise could
	 * lose one bit
	 */
	c.m = 0;
	for(i = 0; i < MBITS+1; i++) {
		c.m <<= 1;
		if(a.m >= b.m) {
			c.m++;
			a.m -= b.m;
		}
		a.m <<= 1;
	}
	if((c.m & f_carry) != 0)
		c.m >>= 1;
	else if((int)--c.e == 0)
		return f_null;
	return c;
}


/*
 * a < b  -> +1
 * a == b ->  0
 * a > b  -> -1
 */
int
F_cmp(struct ifloat a, struct ifloat b)
{
	if(a.e == 0) {
		if(b.e == 0)
			return 0;			/* a == 0 && b == 0 */
		else if(b.s)
			return -1;			/* a == 0 && b < 0 */
		else
			return +1;			/* a == 0 && b > 0 */
	} else if(b.e == 0) {
		if(a.s)
			return +1;			/* a < 0 && b == 0 */
		else
			return -1;			/* a > 0 && b == 0 */
	} else if(a.s && !b.s)
		return +1;				/* a < 0 && b > 0 */
	else if(!a.s && b.s)
		return -1;				/* a > 0 && b < 0 */

	/* signs are equal and numbers not 0 */
	if(a.e > b.e)
		return a.s ? +1 : -1;
	if(a.e < b.e)
		return a.s ? -1 : +1;

	/* exponents and signs are equal */
	if(a.m > b.m)
		return a.s ? +1 : -1;
	if(a.m < b.m)
		return a.s ? -1 : +1;

	return 0;
}

/*
 * return 'broken' part, store integer part in *ip
 */
struct ifloat
F_mod(struct ifloat a, struct ifloat *ip)
{
	struct ifloat c;
	int e;

	/*
	 * a number bigger or equal 2^MBITS is integer anyway
	 */
	if(a.e == 0 || (int)a.e >= (int)EOFFS + MBITS) {
		*ip = a;
		return f_null;
	}

	/*
	 * if the (unoffsetted) exponent is lesser than 0 the number is < 1.0
	 */
	if(a.e < EOFFS) {									/* all 'broken' */
		*ip = f_null;
		return a;
	}

	/*
	 * compute number of bits that are before the dot
	 * we clear the other bits (behind the dot) by shifting them
	 * out
	 */
	e = (int)a.e - EOFFS + 1;
	ip->m = a.m;
	ip->m >>= MBITS - e;
	ip->m <<= MBITS - e;
	ip->e = a.e;
	ip->s = a.s;

	c = F_sub(a, *ip);
	return c;
}


/*
 * real add routine
 * add the absolute values |c|=|a|+|b|, 
 * result has sign of bigger operand
 */
static void
f_add(struct ifloat *a, struct ifloat *b, struct ifloat *c)
{
	struct ifloat *t;

	/*
	 * handle simple cases
	 */
	if(a->e == 0) {		/* a is 0: 0+b=b */
		*c = *b;
		return;
	}
	if(b->e == 0) {		/* b is 0: a+0=a */
		*c = *a;
		return;
	}

	/* 
 	 * a and b are normal and != 0
	 * now make exponent(a) >= exponent(b)
	 */
	if(a->e < b->e) {
		t = a;
		a = b;
		b = t;
	}

	/*
	 * now we now result sign and exponent
	 * mantissa needs alignement if exponents differ
	 */
	c->s = a->s;
	c->e = a->e;
	if(a->e != b->e)	/* could optimize c->e - b->e >= MBITS */
		b->m >>= c->e - b->e;

	/* 
	 * add and don't lose msb carry 
	 * need maximum one shift to normalize
	 */
	c->m = a->m + b->m;
	if(c->m & f_carry) {
		c->m >>= 1;
		c->e++;
	}
}


/*
 * real subtract
 * subtract absolute values |c|=||a|-|b||
 * result has sign of bigger operand 
 */
static void
f_sub(struct ifloat *a, struct ifloat *b, struct ifloat *c)
{
	struct ifloat *t;

	/*
	 * handle simple cases
	 */
	if(a->e == 0) {
		*c = *b;
		return;
	}
	if(b->e == 0) {
		*c = *a;
		return;
	}

	/*
	 * now a and b are normal and not 0
  	 * ensure exponent(a) >= exponent(b)
	 */
	if(b->e > a->e) {
		t = a;
		a = b;
		b = t;
	}

	/*
	 * sign and exponent
	 */
	c->s = a->s;
	c->e = a->e;

	if(b->e != c->e) {
		b->m >>= c->e - b->e;	/* exponent(a) > exponent(c) */
		c->m = a->m - b->m;	/* mant(a) > mant(b) here */
	} else if(a->m == b->m) {	/* gives exact 0 */
		*c = f_null;
		return;
	} else if(a->m > b->m) {	/* no sign change */
		c->m = a->m - b->m;
	} else {			/* b->m > a->m -> sign changes */
		c->s = b->s;
		c->m = b->m - a->m;
	}

	/*
	 * now need to normalize
	 */
	if((c->m & f_msb) == 0)
		f_norm(c);
}

/*
 * normalize number
 */
static void
f_norm(struct ifloat *a)
{
	u_xquad_t m;
	int i;

	if(a->m == 0) {
		*a = f_null;
		return;
	}

	/*
	 * find the first 1 bit in mantissa
	 */
	for(i = -1, m = f_carry; (a->m & m) == 0; m >>= 1, i++)
		;

	/*
	 * loss of precision
	 */
	if((int)a->e - i <= 0) {
		*a = f_null;
		return;
	}
	a->m <<= i;
	a->e = (int)a->e - i;
}
# endif
