/* doubleint.h --
 *
 * rcsid = "$Header: /ufs/repository/magic/utils/doubleint.h,v 1.4 2006/07/08 19:06:55 fang Exp $"
 *
 *     ********************************************************************* 
 *     * Copyright (C) 1985, 1990 Regents of the University of California. * 
 *     * Permission to use, copy, modify, and distribute this              * 
 *     * software and its documentation for any purpose and without        * 
 *     * fee is hereby granted, provided that the above copyright          * 
 *     * notice appear in all copies.  The University of California        * 
 *     * makes no representations about the suitability of this            * 
 *     * software for any purpose.  It is provided "as is" without         * 
 *     * express or implied warranty.  Export of this software outside     * 
 *     * of the United States of America may require an export license.    * 
 *     *********************************************************************
 *		      Lawrence Livermore National Laboratory
 *		      All rights reserved.
 *
 * This file contains definitions for double-precision integer operations.
 */

#ifndef _DOUBLEINT
#define _DOUBLEINT

#include "misc/magic.h"
#include "utils/doubleint_fwd.h"	/* for DoubleInt typedef */

#ifndef ALPHA

#define	CARRYBIT	0x80000000
#define	CARRYMASK	0x7fffffff
#define	CARRYFLOAT	(((double) (0x40000000)) * 2.0)
/* WORDSIZE = #of bits in unsigned long */
#define WORDSIZE	(8 * sizeof(long))

extern DoubleInt DIMaxInt;
extern DoubleInt DIZero;

/* Machine-specific word-order dependencies */

#ifdef	IS_LITTLE_ENDIAN
#	define	SHORT_0		0
#	define	SHORT_1		1
#	define	SHORT_2		2
#	define	SHORT_3		3
#endif

#ifdef	IS_BIG_ENDIAN
#	define	SHORT_0		1
#	define	SHORT_1		0
#	define	SHORT_2		3
#	define	SHORT_3		2
#endif

/* Error checking to maintain consistency of this file. */
#ifndef SHORT_0
    Error_1 = You_need_to_define_the_ENDIAN_constants_in_magic.h;
#endif

extern void DoubleInit();	/* Initialize this package. */
DoubleInt DoubleMultI();	/* multiply double by unsigned long */
DoubleInt DoubleMultII();	/* multiply unsigned long by unsigned long */
DoubleInt DoubleAdd();		/* add two doubles */
void DoubleString(DoubleInt, register char*);
				/* convert double int to string */
double DoubleToDFloat();	/* convert double int  to double float */

/*
 * DOUBLE_CREATE --
 *
 * Set 'result' to be the double-precision integer corresponding
 * to 'n'
 */
#define	DOUBLE_CREATE(result, n) \
    { \
	(result).di_low = (n) & CARRYMASK; \
	(result).di_high = ((n) & CARRYBIT) ? 1 : 0; \
    }

/*
 * DOUBLE_ADD --
 *
 * Set 'result' to be the sum of the two DoubleInts n1 and n2.
 */
#define	DOUBLE_ADD(result, n1, n2) \
    { \
	register unsigned long __r = (n1).di_low + (n2).di_low; \
	(result).di_low = (__r & CARRYMASK); \
	(result).di_high = (n1).di_high + (n2).di_high + ((__r&CARRYBIT) ?1 :0); \
    }

/*
 * DOUBLE_ADDI --
 *
 * Set 'result' to be the sum of the DoubleInts n1 and the unsigned long i.
 */
#define	DOUBLE_ADDI(result, n1, i) \
    { \
	register unsigned long __r = (n1).di_low + (i); \
	(result).di_low = (__r & CARRYMASK); \
	(result).di_high = (n1).di_high + ((__r&CARRYBIT) ?1 :0); \
    }
  
/*
 * DOUBLE_SUB --
 *
 * Set 'result' to be the difference of the two DoubleInts n1 and n2.
 * (NOTE: it is assumed that n2<=n1, since we are only doing positive 
 * arithmetic).
 */
#define	DOUBLE_SUB(result, n1, n2) \
    { \
	register unsigned long __r = ((n1).di_low | CARRYBIT) - (n2).di_low; \
	(result).di_low = (__r & CARRYMASK); \
	(result).di_high = (n1).di_high - (n2).di_high - ((__r&CARRYBIT) ?0 :1); \
    }

/*
 * DOUBLE_SUBI --
 *
 * Set 'result' to be the difference of the DoubleInt n1 and the 
 * unsigned long i.
 * (NOTE: it is assumed that i<=n1, since we are only doing positive 
 * arithmetic).
 */
#define	DOUBLE_SUBI(result, n1, i) \
    { \
	register unsigned long __r = ((n1).di_low | CARRYBIT) - (i); \
	(result).di_low = (__r & CARRYMASK); \
	(result).di_high = (n1).di_high - ((__r&CARRYBIT) ?0 :1); \
    }

/* comparisons */

/*
 * DOUBLE_GREATER --
 */
#define	DOUBLE_GREATER(n1, n2)	\
	((n1).di_high > (n2).di_high \
		    ? 1 : ((n1).di_high < (n2).di_high \
			    ? 0 : (n1).di_low > (n2).di_low))

/* 
 * DOUBLE_GE --
 */
#define	DOUBLE_GE(n1, n2)	\
	((n1).di_high > (n2).di_high \
		    ? 1 : ((n1).di_high < (n2).di_high \
			    ? 0 : (n1).di_low >= (n2).di_low))

/* 
 * DOUBLE_LESS --
 */
#define	DOUBLE_LESS(n1, n2)	\
	((n1).di_high < (n2).di_high \
		    ? 1 : ((n1).di_high > (n2).di_high \
			    ? 0 : (n1).di_low < (n2).di_low))

/* 
 * DOUBLE_LE --
 */
#define	DOUBLE_LE(n1, n2)	\
	((n1).di_high < (n2).di_high \
		    ? 1 : ((n1).di_high > (n2).di_high \
			    ? 0 : (n1).di_low <= (n2).di_low))
/*
 * DOUBLE_EQUAL --
 */
#define	DOUBLE_EQUAL(n1, n2)	\
	((n1).di_high == (n2).di_high && (n1).di_low == (n2).di_low)

/*
 * DOUBLE_SHIFTRIGHT --
 *
 * Set 'result' to be doubleint n1/(2**e).
 * (NOTE:  e must be: 0<=e<=WORDSIZE-1)
 */
#define	DOUBLE_SHIFTRIGHT(result, n1, e) \
    { \
	(result).di_low = \
		((n1).di_low>>(e) | (n1).di_high<<(WORDSIZE-(e)-1)) & \
		~CARRYBIT; \
	(result).di_high = (n1).di_high>>(e); \
    }

/*
 * DOUBLE_SHIFTLEFT --
 *
 * Set 'result' to be doubleint n1*(2**e).
 * (NOTE:  e must be: 0<=e<=WORDSIZE-1)
 */
#define	DOUBLE_SHIFTLEFT(result, n1, e) \
    { \
	(result).di_high = \
		((n1).di_high<<(e) | (n1).di_low>>(WORDSIZE-(e)-1)); \
	(result).di_low = (n1).di_low<<(e) & ~CARRYBIT; \
    }

#else /* ALPHA-AXP or 64 bits architectire */


typedef	long	DoubleInt;

/* WORDSIZE = #of bits in unsigned long */
#define WORDSIZE	(8 * sizeof(int))

extern DoubleInt DIMaxInt;
extern DoubleInt DIZero;

/* Machine-specific word-order dependencies */

#ifdef	IS_LITTLE_ENDIAN
#	define	SHORT_0		0
#	define	SHORT_1		1
#	define	SHORT_2		2
#	define	SHORT_3		3
#endif

#ifdef	IS_BIG_ENDIAN
#	define	SHORT_0		1
#	define	SHORT_1		0
#	define	SHORT_2		3
#	define	SHORT_3		2
#endif

/* Error checking to maintain consistency of this file. */
#ifndef SHORT_0
    Error_1 = You_need_to_define_the_ENDIAN_constants_in_magic.h;
#endif

extern void DoubleInit();	/* Initialize this package. */
DoubleInt DoubleMultI();	/* multiply double by unsigned long */
DoubleInt DoubleMultII();	/* multiply unsigned long by unsigned long */
DoubleInt DoubleAdd();		/* add two doubles */
Void DoubleString();		/* convert double int to string */
double DoubleToDFloat();	/* convert double int  to double float */

/*
 * DOUBLE_CREATE --
 *
 * Set 'result' to be the double-precision integer corresponding
 * to 'n'
 */
#define	DOUBLE_CREATE(result, n) \
    { \
	result = ( long ) (n) ; \
    }

/*
 * DOUBLE_ADD --
 *
 * Set 'result' to be the sum of the two DoubleInts n1 and n2.
 */
#define	DOUBLE_ADD(result, n1, n2) \
    { \
	result = (n1) + (n2) ; \
    }

/*
 * DOUBLE_ADDI --
 *
 * Set 'result' to be the sum of the DoubleInts n1 and the unsigned long i.
 */
#define	DOUBLE_ADDI(result, n1, i) \
    { \
	result = (n1) + (long) (i);\
    }
  
/*
 * DOUBLE_SUB --
 *
 * Set 'result' to be the difference of the two DoubleInts n1 and n2.
 * (NOTE: it is assumed that n2<=n1, since we are only doing positive 
 * arithmetic).
 */
#define	DOUBLE_SUB(result, n1, n2) \
    { \
	result = (n1) - (n2) ;\
    }

/*
 * DOUBLE_SUBI --
 *
 * Set 'result' to be the difference of the DoubleInt n1 and the 
 * unsigned long i.
 * (NOTE: it is assumed that i<=n1, since we are only doing positive 
 * arithmetic).
 */
#define	DOUBLE_SUBI(result, n1, i) \
    { \
	result = (n1) - (i) ; \
    }

/* comparisons */

/*
 * DOUBLE_GREATER --
 */
#define	DOUBLE_GREATER(n1, n2)	\
	( (n1) > (n2) )

/* 
 * DOUBLE_GE --
 */
#define	DOUBLE_GE(n1, n2)	\
	( (n1) >= (n2) )

/* 
 * DOUBLE_LESS --
 */
#define	DOUBLE_LESS(n1, n2)	\
	( (n1) < (n2) )

/* 
 * DOUBLE_LE --
 */
#define	DOUBLE_LE(n1, n2)	\
	( (n1) <= (n2) )

/*
 * DOUBLE_EQUAL --
 */
#define	DOUBLE_EQUAL(n1, n2)	\
	( (n1) == (n2) )

/*
 * DOUBLE_SHIFTRIGHT --
 *
 * Set 'result' to be doubleint n1/(2**e).
 * (NOTE:  e must be: 0<=e<=WORDSIZE-1)
 */
#define	DOUBLE_SHIFTRIGHT(result, n1, e) \
    { \
	(result) = (n1) >> (e); \
    }

/*
 * DOUBLE_SHIFTLEFT --
 *
 * Set 'result' to be doubleint n1*(2**e).
 * (NOTE:  e must be: 0<=e<=WORDSIZE-1)
 */
#define	DOUBLE_SHIFTLEFT(result, n1, e) \
    { \
	(result) = (n1) << (e); \
    }


#endif

#endif /* _DOUBLEINT */
