244 lines
6.1 KiB
C
244 lines
6.1 KiB
C
/***
|
|
*tenpow.c - multiply a _LDBL12 by a power of 10
|
|
*
|
|
* Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
*
|
|
*Revision History:
|
|
* 07-17-91 GDP Initial version (ported from assembly)
|
|
* 11-15-93 GJF Merged in NT SDK verions. Replaced MIPS and _ALPHA_
|
|
* by _M_MRX000 and _M_ALPHA (resp.).
|
|
* 10-02-94 BWT PPC changes
|
|
* 07-15-96 GJF Added parantheses to fix precedence problem in expr.
|
|
* Also, detab-ed.
|
|
* 05-05-99 RDL Added _M_IA64 to #if def's for alignment.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
|
|
#include <cv.h>
|
|
|
|
extern _LDBL12 _pow10pos[];
|
|
extern _LDBL12 _pow10neg[];
|
|
|
|
|
|
|
|
|
|
/***
|
|
*void _CALLTYPE5 __ld12mul(_LDBL12 *px, _LDBL12 *py) -
|
|
* _LDBL12 multiplication
|
|
*
|
|
*Purpose: multiply two _LDBL12 numbers
|
|
*
|
|
*Entry: px,py: pointers to the _LDBL12 operands
|
|
*
|
|
*Exit: *px contains the product
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void _CALLTYPE5 __ld12mul(_LDBL12 *px, _LDBL12 *py)
|
|
{
|
|
u_short sign = 0;
|
|
_LDBL12 tempman; /*this is actually a 12-byte mantissa,
|
|
not a 12-byte long double */
|
|
int i;
|
|
u_short expx, expy, expsum;
|
|
int roffs,poffs,qoffs;
|
|
int sticky = 0;
|
|
|
|
*UL_LO_12(&tempman) = 0;
|
|
*UL_MED_12(&tempman) = 0;
|
|
*UL_HI_12(&tempman) = 0;
|
|
|
|
expx = *U_EXP_12(px);
|
|
expy = *U_EXP_12(py);
|
|
|
|
sign = (expx ^ expy) & (u_short)0x8000;
|
|
expx &= 0x7fff;
|
|
expy &= 0x7fff;
|
|
expsum = expx+expy;
|
|
if (expx >= LD_MAXEXP
|
|
|| expy >= LD_MAXEXP
|
|
|| expsum > LD_MAXEXP+ LD_BIASM1){
|
|
/* overflow to infinity */
|
|
PUT_INF_12(px,sign);
|
|
return;
|
|
}
|
|
if (expsum <= LD_BIASM1-63) {
|
|
/* underflow to zero */
|
|
PUT_ZERO_12(px);
|
|
return;
|
|
}
|
|
if (expx == 0) {
|
|
/*
|
|
* If this is a denormal temp real then the mantissa
|
|
* was shifted right once to set bit 63 to zero.
|
|
*/
|
|
expsum++; /* Correct for this */
|
|
if (ISZERO_12(px)) {
|
|
/* put positive sign */
|
|
*U_EXP_12(px) = 0;
|
|
return;
|
|
}
|
|
}
|
|
if (expy == 0) {
|
|
expsum++; /* because arg2 is denormal */
|
|
if (ISZERO_12(py)) {
|
|
PUT_ZERO_12(px);
|
|
return;
|
|
}
|
|
}
|
|
|
|
roffs = 0;
|
|
for (i=0;i<5;i++) {
|
|
int j;
|
|
poffs = i<<1;
|
|
qoffs = 8;
|
|
for (j=5-i;j>0;j--) {
|
|
u_long prod;
|
|
#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC) || defined(_M_IA64)
|
|
/* a variable to hold temprary sums */
|
|
u_long sum;
|
|
#endif
|
|
int carry;
|
|
u_short *p, *q;
|
|
u_long *r;
|
|
p = USHORT_12(px,poffs);
|
|
q = USHORT_12(py,qoffs);
|
|
r = ULONG_12(&tempman,roffs);
|
|
prod = (u_long)*p * (u_long)*q;
|
|
#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC) || defined(_M_IA64)
|
|
/* handle misalignment problems */
|
|
if (i&0x1){ /* i is odd */
|
|
carry = __addl(*ALIGN(r), prod, &sum);
|
|
*ALIGN(r) = sum;
|
|
}
|
|
else /* i is even */
|
|
carry = __addl(*r, prod, r);
|
|
#else
|
|
carry = __addl(*r,prod,r);
|
|
#endif
|
|
if (carry) {
|
|
/* roffs should be less than 8 in this case */
|
|
(*USHORT_12(&tempman,roffs+4))++;
|
|
}
|
|
poffs+=2;
|
|
qoffs-=2;
|
|
}
|
|
roffs+=2;
|
|
}
|
|
|
|
expsum -= LD_BIASM1;
|
|
|
|
/* normalize */
|
|
while ((s_short)expsum > 0 &&
|
|
((*UL_HI_12(&tempman) & MSB_ULONG) == 0)) {
|
|
__shl_12(&tempman);
|
|
expsum--;
|
|
}
|
|
|
|
if ((s_short)expsum <= 0) {
|
|
expsum--;
|
|
while ((s_short)expsum < 0) {
|
|
if (*U_XT_12(&tempman) & 0x1)
|
|
sticky++;
|
|
__shr_12(&tempman);
|
|
expsum++;
|
|
}
|
|
if (sticky)
|
|
*U_XT_12(&tempman) |= 0x1;
|
|
}
|
|
|
|
if (*U_XT_12(&tempman) > 0x8000 ||
|
|
((*UL_LO_12(&tempman) & 0x1ffff) == 0x18000)) {
|
|
/* round up */
|
|
if (*UL_MANLO_12(&tempman) == MAX_ULONG) {
|
|
*UL_MANLO_12(&tempman) = 0;
|
|
if (*UL_MANHI_12(&tempman) == MAX_ULONG) {
|
|
*UL_MANHI_12(&tempman) = 0;
|
|
if (*U_EXP_12(&tempman) == MAX_USHORT) {
|
|
/* 12-byte mantissa overflow */
|
|
*U_EXP_12(&tempman) = MSB_USHORT;
|
|
expsum++;
|
|
}
|
|
else
|
|
(*U_EXP_12(&tempman))++;
|
|
}
|
|
else
|
|
(*UL_MANHI_12(&tempman))++;
|
|
}
|
|
else
|
|
(*UL_MANLO_12(&tempman))++;
|
|
}
|
|
|
|
|
|
/* check for exponent overflow */
|
|
if (expsum >= 0x7fff){
|
|
PUT_INF_12(px, sign);
|
|
return;
|
|
}
|
|
|
|
/* put result in px */
|
|
*U_XT_12(px) = *USHORT_12(&tempman,2);
|
|
*UL_MANLO_12(px) = *UL_MED_12(&tempman);
|
|
*UL_MANHI_12(px) = *UL_HI_12(&tempman);
|
|
*U_EXP_12(px) = expsum | sign;
|
|
}
|
|
|
|
|
|
|
|
void _CALLTYPE5
|
|
__multtenpow12(_LDBL12 *pld12, int pow, unsigned mult12)
|
|
{
|
|
_LDBL12 *pow_10p = _pow10pos-8;
|
|
if (pow == 0)
|
|
return;
|
|
if (pow < 0) {
|
|
pow = -pow;
|
|
pow_10p = _pow10neg-8;
|
|
}
|
|
|
|
if (!mult12)
|
|
*U_XT_12(pld12) = 0;
|
|
|
|
|
|
while (pow) {
|
|
int last3; /* the 3 LSBits of pow */
|
|
_LDBL12 unround;
|
|
_LDBL12 *py;
|
|
|
|
pow_10p += 7;
|
|
last3 = pow & 0x7;
|
|
pow >>= 3;
|
|
if (last3 == 0)
|
|
continue;
|
|
py = pow_10p + last3;
|
|
|
|
#ifdef _LDSUPPORT
|
|
if (mult12) {
|
|
#endif
|
|
/* do an exact 12byte multiplication */
|
|
if (*U_XT_12(py) >= 0x8000) {
|
|
/* copy number */
|
|
unround = *py;
|
|
/* unround adjacent byte */
|
|
(*UL_MANLO_12(&unround))--;
|
|
/* point to new operand */
|
|
py = &unround;
|
|
}
|
|
__ld12mul(pld12,py);
|
|
#ifdef _LDSUPPORT
|
|
}
|
|
else {
|
|
/* do a 10byte multiplication */
|
|
py = (_LDBL12 *)TEN_BYTE_PART(py);
|
|
*(long double *)TEN_BYTE_PART(pld12) *=
|
|
*(long double *)py;
|
|
}
|
|
#endif
|
|
}
|
|
}
|