windows-nt/Source/XPSP1/NT/sdktools/debuggers/dbg-common/float10.cpp

2171 lines
50 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/***
*float10.c - floating point output for 10-byte long double
*
* Copyright (c) 1991-1991, Microsoft Corporation. All rights reserved.
*
*Purpose:
* Support conversion of a long double into a string
*
*Revision History:
* 07/15/91 GDP Initial version in C (ported from assembly)
* 01/23/92 GDP Support MIPS encoding for NaN
* 05-26-92 GWK Windbg srcs
*
******************************************************************************/
#include "pch.hpp"
#include <math.h>
#include "float10.h"
typedef LONG s_long;
typedef ULONG u_long;
typedef SHORT s_short;
typedef USHORT u_short;
#define L_END
#define PTR_LD(x) ((u_char *)(&(x)->ld))
#define PTR_12(x) ((u_char *)(&(x)->ld12))
#define MAX_USHORT ((u_short)0xffff)
#define MSB_USHORT ((u_short)0x8000)
#define MAX_ULONG ((u_long)0xffffffff)
#define MSB_ULONG ((u_long)0x80000000)
#define TMAX10 5200 /* maximum temporary decimal exponent */
#define TMIN10 -5200 /* minimum temporary decimal exponent */
#define LD_MAX_EXP_LEN 4 /* maximum number of decimal exponent digits */
#define LD_MAX_MAN_LEN 24 /* maximum length of mantissa (decimal)*/
#define LD_MAX_MAN_LEN1 25 /* MAX_MAN_LEN+1 */
#define LD_BIAS 0x3fff /* exponent bias for long double */
#define LD_BIASM1 0x3ffe /* LD_BIAS - 1 */
#define LD_MAXEXP 0x7fff /* maximum biased exponent */
#define D_BIAS 0x3ff /* exponent bias for double */
#define D_BIASM1 0x3fe /* D_BIAS - 1 */
#define D_MAXEXP 0x7ff /* maximum biased exponent */
/* Recognizing special patterns in the mantissa field */
#define _EXP_SP 0x7fff
#define NAN_BIT (1<<30)
#define _IS_MAN_INF(signbit, manhi, manlo) \
( (manhi)==MSB_ULONG && (manlo)==0x0 )
#define _IS_MAN_IND(signbit, manhi, manlo) \
((signbit) && (manhi)==0xc0000000 && (manlo)==0)
#define _IS_MAN_QNAN(signbit, manhi, manlo) \
( (manhi)&NAN_BIT )
#define _IS_MAN_SNAN(signbit, manhi, manlo) \
(!( _IS_MAN_INF(signbit, manhi, manlo) || \
_IS_MAN_QNAN(signbit, manhi, manlo) ))
/*
* Manipulation of a 12-byte long double number (an ordinary
* 10-byte long double plus two extra bytes of mantissa).
*/
/* a pointer to the exponent/sign portion */
#define U_EXP_12(p) ((u_short *)(PTR_12(p)+10))
/* a pointer to the 4 hi-order bytes of the mantissa */
#define UL_MANHI_12(p) ((u_long UNALIGNED *)(PTR_12(p)+6))
/* a pointer to the 4 lo-order bytes of the ordinary (8-byte) mantissa */
#define UL_MANLO_12(p) ((u_long UNALIGNED *)(PTR_12(p)+2))
/* a pointer to the 2 extra bytes of the mantissa */
#define U_XT_12(p) ((u_short *)PTR_12(p))
/* a pointer to the 4 lo-order bytes of the extended (10-byte) mantissa */
#define UL_LO_12(p) ((u_long UNALIGNED *)PTR_12(p))
/* a pointer to the 4 mid-order bytes of the extended (10-byte) mantissa */
#define UL_MED_12(p) ((u_long UNALIGNED *)(PTR_12(p)+4))
/* a pointer to the 4 hi-order bytes of the extended long double */
#define UL_HI_12(p) ((u_long UNALIGNED *)(PTR_12(p)+8))
/* a pointer to the byte of order i (LSB=0, MSB=9)*/
#define UCHAR_12(p,i) ((u_char *)PTR_12(p)+(i))
/* a pointer to a u_short with offset i */
#define USHORT_12(p,i) ((u_short *)((u_char *)PTR_12(p)+(i)))
/* a pointer to a u_long with offset i */
#define ULONG_12(p,i) ((u_long UNALIGNED *)((u_char *)PTR_12(p)+(i)))
/* a pointer to the 10 MSBytes of a 12-byte long double */
#define TEN_BYTE_PART(p) ((u_char *)PTR_12(p)+2)
/*
* Manipulation of a 10-byte long double number
*/
#define U_EXP_LD(p) ((u_short *)(PTR_LD(p)+8))
#define UL_MANHI_LD(p) ((u_long UNALIGNED *)(PTR_LD(p)+4))
#define UL_MANLO_LD(p) ((u_long UNALIGNED *)PTR_LD(p))
/*
* Manipulation of a 64bit IEEE double
*/
#define U_SHORT4_D(p) ((u_short *)(p) + 3)
#define UL_HI_D(p) ((u_long UNALIGNED *)(p) + 1)
#define UL_LO_D(p) ((u_long UNALIGNED *)(p))
#define PUT_INF_12(p,sign) \
*UL_HI_12(p) = (sign)?0xffff8000:0x7fff8000; \
*UL_MED_12(p) = 0; \
*UL_LO_12(p) = 0;
#define PUT_ZERO_12(p) *UL_HI_12(p) = 0; \
*UL_MED_12(p) = 0; \
*UL_LO_12(p) = 0;
#define ISZERO_12(p) ((*UL_HI_12(p)&0x7fffffff) == 0 && \
*UL_MED_12(p) == 0 && \
*UL_LO_12(p) == 0 )
#define PUT_INF_LD(p,sign) \
*U_EXP_LD(p) = (sign)?0xffff:0x7fff; \
*UL_MANHI_LD(p) = 0x8000; \
*UL_MANLO_LD(p) = 0;
#define PUT_ZERO_LD(p) *U_EXP_LD(p) = 0; \
*UL_MANHI_LD(p) = 0; \
*UL_MANLO_LD(p) = 0;
#define ISZERO_LD(p) ((*U_EXP_LD(p)&0x7fff) == 0 && \
*UL_MANHI_LD(p) == 0 && \
*UL_MANLO_LD(p) == 0 )
/* Format: A 10 byte long double + 2 bytes of extra precision
* If the extra precision is desired, the 10-byte long double
* should be "unrounded" first.
* This may change in later versions
*/
#ifdef L_END
_ULDBL12 _pow10pos[] = {
/*P0001*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0x02,0x40}},
/*P0002*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x05,0x40}},
/*P0003*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFA,0x08,0x40}},
/*P0004*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9C,0x0C,0x40}},
/*P0005*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xC3,0x0F,0x40}},
/*P0006*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x24,0xF4,0x12,0x40}},
/*P0007*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0x96,0x98,0x16,0x40}},
/*P0008*/ {{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x20,0xBC,0xBE,0x19,0x40}},
/*P0016*/ {{0x00,0x00, 0x00,0x00,0x00,0x04,0xBF,0xC9,0x1B,0x8E,0x34,0x40}},
/*P0024*/ {{0x00,0x00, 0x00,0xA1,0xED,0xCC,0xCE,0x1B,0xC2,0xD3,0x4E,0x40}},
/*P0032*/ {{0x20,0xF0, 0x9E,0xB5,0x70,0x2B,0xA8,0xAD,0xC5,0x9D,0x69,0x40}},
/*P0040*/ {{0xD0,0x5D, 0xFD,0x25,0xE5,0x1A,0x8E,0x4F,0x19,0xEB,0x83,0x40}},
/*P0048*/ {{0x71,0x96, 0xD7,0x95,0x43,0x0E,0x05,0x8D,0x29,0xAF,0x9E,0x40}},
/*P0056*/ {{0xF9,0xBF, 0xA0,0x44,0xED,0x81,0x12,0x8F,0x81,0x82,0xB9,0x40}},
/*P0064*/ {{0xBF,0x3C, 0xD5,0xA6,0xCF,0xFF,0x49,0x1F,0x78,0xC2,0xD3,0x40}},
/*P0128*/ {{0x6F,0xC6, 0xE0,0x8C,0xE9,0x80,0xC9,0x47,0xBA,0x93,0xA8,0x41}},
/*P0192*/ {{0xBC,0x85, 0x6B,0x55,0x27,0x39,0x8D,0xF7,0x70,0xE0,0x7C,0x42}},
/*P0256*/ {{0xBC,0xDD, 0x8E,0xDE,0xF9,0x9D,0xFB,0xEB,0x7E,0xAA,0x51,0x43}},
/*P0320*/ {{0xA1,0xE6, 0x76,0xE3,0xCC,0xF2,0x29,0x2F,0x84,0x81,0x26,0x44}},
/*P0384*/ {{0x28,0x10, 0x17,0xAA,0xF8,0xAE,0x10,0xE3,0xC5,0xC4,0xFA,0x44}},
/*P0448*/ {{0xEB,0xA7, 0xD4,0xF3,0xF7,0xEB,0xE1,0x4A,0x7A,0x95,0xCF,0x45}},
/*P0512*/ {{0x65,0xCC, 0xC7,0x91,0x0E,0xA6,0xAE,0xA0,0x19,0xE3,0xA3,0x46}},
/*P1024*/ {{0x0D,0x65, 0x17,0x0C,0x75,0x81,0x86,0x75,0x76,0xC9,0x48,0x4D}},
/*P1536*/ {{0x58,0x42, 0xE4,0xA7,0x93,0x39,0x3B,0x35,0xB8,0xB2,0xED,0x53}},
/*P2048*/ {{0x4D,0xA7, 0xE5,0x5D,0x3D,0xC5,0x5D,0x3B,0x8B,0x9E,0x92,0x5A}},
/*P2560*/ {{0xFF,0x5D, 0xA6,0xF0,0xA1,0x20,0xC0,0x54,0xA5,0x8C,0x37,0x61}},
/*P3072*/ {{0xD1,0xFD, 0x8B,0x5A,0x8B,0xD8,0x25,0x5D,0x89,0xF9,0xDB,0x67}},
/*P3584*/ {{0xAA,0x95, 0xF8,0xF3,0x27,0xBF,0xA2,0xC8,0x5D,0xDD,0x80,0x6E}},
/*P4096*/ {{0x4C,0xC9, 0x9B,0x97,0x20,0x8A,0x02,0x52,0x60,0xC4,0x25,0x75}}
};
_ULDBL12 _pow10neg[] = {
/*N0001*/ {{0xCD,0xCC, 0xCD,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFB,0x3F}},
/*N0002*/ {{0x71,0x3D, 0x0A,0xD7,0xA3,0x70,0x3D,0x0A,0xD7,0xA3,0xF8,0x3F}},
/*N0003*/ {{0x5A,0x64, 0x3B,0xDF,0x4F,0x8D,0x97,0x6E,0x12,0x83,0xF5,0x3F}},
/*N0004*/ {{0xC3,0xD3, 0x2C,0x65,0x19,0xE2,0x58,0x17,0xB7,0xD1,0xF1,0x3F}},
/*N0005*/ {{0xD0,0x0F, 0x23,0x84,0x47,0x1B,0x47,0xAC,0xC5,0xA7,0xEE,0x3F}},
/*N0006*/ {{0x40,0xA6, 0xB6,0x69,0x6C,0xAF,0x05,0xBD,0x37,0x86,0xEB,0x3F}},
/*N0007*/ {{0x33,0x3D, 0xBC,0x42,0x7A,0xE5,0xD5,0x94,0xBF,0xD6,0xE7,0x3F}},
/*N0008*/ {{0xC2,0xFD, 0xFD,0xCE,0x61,0x84,0x11,0x77,0xCC,0xAB,0xE4,0x3F}},
/*N0016*/ {{0x2F,0x4C, 0x5B,0xE1,0x4D,0xC4,0xBE,0x94,0x95,0xE6,0xC9,0x3F}},
/*N0024*/ {{0x92,0xC4, 0x53,0x3B,0x75,0x44,0xCD,0x14,0xBE,0x9A,0xAF,0x3F}},
/*N0032*/ {{0xDE,0x67, 0xBA,0x94,0x39,0x45,0xAD,0x1E,0xB1,0xCF,0x94,0x3F}},
/*N0040*/ {{0x24,0x23, 0xC6,0xE2,0xBC,0xBA,0x3B,0x31,0x61,0x8B,0x7A,0x3F}},
/*N0048*/ {{0x61,0x55, 0x59,0xC1,0x7E,0xB1,0x53,0x7C,0x12,0xBB,0x5F,0x3F}},
/*N0056*/ {{0xD7,0xEE, 0x2F,0x8D,0x06,0xBE,0x92,0x85,0x15,0xFB,0x44,0x3F}},
/*N0064*/ {{0x24,0x3F, 0xA5,0xE9,0x39,0xA5,0x27,0xEA,0x7F,0xA8,0x2A,0x3F}},
/*N0128*/ {{0x7D,0xAC, 0xA1,0xE4,0xBC,0x64,0x7C,0x46,0xD0,0xDD,0x55,0x3E}},
/*N0192*/ {{0x63,0x7B, 0x06,0xCC,0x23,0x54,0x77,0x83,0xFF,0x91,0x81,0x3D}},
/*N0256*/ {{0x91,0xFA, 0x3A,0x19,0x7A,0x63,0x25,0x43,0x31,0xC0,0xAC,0x3C}},
/*N0320*/ {{0x21,0x89, 0xD1,0x38,0x82,0x47,0x97,0xB8,0x00,0xFD,0xD7,0x3B}},
/*N0384*/ {{0xDC,0x88, 0x58,0x08,0x1B,0xB1,0xE8,0xE3,0x86,0xA6,0x03,0x3B}},
/*N0448*/ {{0xC6,0x84, 0x45,0x42,0x07,0xB6,0x99,0x75,0x37,0xDB,0x2E,0x3A}},
/*N0512*/ {{0x33,0x71, 0x1C,0xD2,0x23,0xDB,0x32,0xEE,0x49,0x90,0x5A,0x39}},
/*N1024*/ {{0xA6,0x87, 0xBE,0xC0,0x57,0xDA,0xA5,0x82,0xA6,0xA2,0xB5,0x32}},
/*N1536*/ {{0xE2,0x68, 0xB2,0x11,0xA7,0x52,0x9F,0x44,0x59,0xB7,0x10,0x2C}},
/*N2048*/ {{0x25,0x49, 0xE4,0x2D,0x36,0x34,0x4F,0x53,0xAE,0xCE,0x6B,0x25}},
/*N2560*/ {{0x8F,0x59, 0x04,0xA4,0xC0,0xDE,0xC2,0x7D,0xFB,0xE8,0xC6,0x1E}},
/*N3072*/ {{0x9E,0xE7, 0x88,0x5A,0x57,0x91,0x3C,0xBF,0x50,0x83,0x22,0x18}},
/*N3584*/ {{0x4E,0x4B, 0x65,0x62,0xFD,0x83,0x8F,0xAF,0x06,0x94,0x7D,0x11}},
/*N4096*/ {{0xE4,0x2D, 0xDE,0x9F,0xCE,0xD2,0xC8,0x04,0xDD,0xA6,0xD8,0x0A}}
};
#endif
int __addl(u_long x, u_long y, u_long UNALIGNED *sum)
{
u_long r;
int carry=0;
r = x+y;
if (r < x || r < y)
carry++;
*sum = r;
return carry;
}
/***
*void __add_12(_ULDBL12 *x, _ULDBL12 *y) - _ULDBL12 addition
*
*Purpose: add two _ULDBL12 numbers. The numbers are added
* as 12-byte integers. Overflow is ignored.
*
*Entry: x,y: pointers to the operands
*
*Exit: *x receives the sum
*
*Exceptions:
*
*******************************************************************************/
void __add_12(_ULDBL12 *x, _ULDBL12 *y)
{
int c0,c1,c2;
c0 = __addl(*UL_LO_12(x),*UL_LO_12(y),UL_LO_12(x));
if (c0) {
c1 = __addl(*UL_MED_12(x),(u_long)1,UL_MED_12(x));
if (c1) {
(*UL_HI_12(x))++;
}
}
c2 = __addl(*UL_MED_12(x),*UL_MED_12(y),UL_MED_12(x));
if (c2) {
(*UL_HI_12(x))++;
}
/* ignore next carry -- assume no overflow will occur */
(void) __addl(*UL_HI_12(x),*UL_HI_12(y),UL_HI_12(x));
}
/***
*void __shl_12(_ULDBL12 *x) - _ULDBL12 shift left
*void __shr_12(_ULDBL12 *x) - _ULDBL12 shift right
*
*Purpose: Shift a _ULDBL12 number one bit to the left (right). The number
* is shifted as a 12-byte integer. The MSB is lost.
*
*Entry: x: a pointer to the operand
*
*Exit: *x is shifted one bit to the left (or right)
*
*Exceptions:
*
*******************************************************************************/
void __shl_12(_ULDBL12 *p)
{
u_long c0,c1;
c0 = *UL_LO_12(p) & MSB_ULONG ? 1: 0;
c1 = *UL_MED_12(p) & MSB_ULONG ? 1: 0;
*UL_LO_12(p) <<= 1;
*UL_MED_12(p) = *UL_MED_12(p)<<1 | c0;
*UL_HI_12(p) = *UL_HI_12(p)<<1 | c1;
}
void __shr_12(_ULDBL12 *p)
{
u_long c2,c1;
c2 = *UL_HI_12(p) & 0x1 ? MSB_ULONG: 0;
c1 = *UL_MED_12(p) & 0x1 ? MSB_ULONG: 0;
*UL_HI_12(p) >>= 1;
*UL_MED_12(p) = *UL_MED_12(p)>>1 | c2;
*UL_LO_12(p) = *UL_LO_12(p)>>1 | c1;
}
/***
*void __ld12mul(_ULDBL12 *px, _ULDBL12 *py) -
* _ULDBL12 multiplication
*
*Purpose: multiply two _ULDBL12 numbers
*
*Entry: px,py: pointers to the _ULDBL12 operands
*
*Exit: *px contains the product
*
*Exceptions:
*
*******************************************************************************/
void __ld12mul(_ULDBL12 *px, _ULDBL12 *py)
{
u_short sign = 0;
u_short sticky_bits = 0;
_ULDBL12 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;
*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;
#ifdef MIPS
/* a variable to hold temprary sums */
u_long sum;
#endif
int carry;
u_short *p, *q;
u_long UNALIGNED *r;
p = USHORT_12(px,poffs);
q = USHORT_12(py,qoffs);
r = ULONG_12(&tempman,roffs);
prod = (u_long)*p * (u_long)*q;
#ifdef MIPS
/* handle misalignment problems */
if (i&0x1){ /* i is odd */
carry = __addl(*MIPSALIGN(r), prod, &sum);
*MIPSALIGN(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--;
sticky = 0;
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 __multtenpow12(_ULDBL12 *pld12, int pow, unsigned mult12)
{
_ULDBL12 *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 */
_ULDBL12 unround;
_ULDBL12 *py;
pow_10p += 7;
last3 = pow & 0x7;
pow >>= 3;
if (last3 == 0)
continue;
py = pow_10p + last3;
#ifdef _ULDSUPPORT
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 _ULDSUPPORT
}
else {
/* do a 10byte multiplication */
py = (_ULDBL12 *)TEN_BYTE_PART(py);
*(long double *)TEN_BYTE_PART(pld12) *=
*(long double *)py;
}
#endif
}
}
/***
*void __mtold12(char *manptr,unsigned manlen,_ULDBL12 *ld12) -
* convert a mantissa into a _ULDBL12
*
*Purpose: convert a mantissa into a _ULDBL12. The mantissa is
* in the form of an array of manlen BCD digits and is
* considered to be an integer.
*
*Entry: manptr: the array containing the packed BCD digits of the mantissa
* manlen: the size of the array
* ld12: a pointer to the long double where the result will be stored
*
*Exit:
* ld12 gets the result of the conversion
*
*Exceptions:
*
*******************************************************************************/
void __mtold12(char *manptr,
unsigned manlen,
_ULDBL12 *ld12)
{
_ULDBL12 tmp;
u_short expn = LD_BIASM1+80;
*UL_LO_12(ld12) = 0;
*UL_MED_12(ld12) = 0;
*UL_HI_12(ld12) = 0;
for (;manlen>0;manlen--,manptr++){
tmp = *ld12;
__shl_12(ld12);
__shl_12(ld12);
__add_12(ld12,&tmp);
__shl_12(ld12); /* multiply by 10 */
*UL_LO_12(&tmp) = (u_long)*manptr;
*UL_MED_12(&tmp) = 0;
*UL_HI_12(&tmp) = 0;
__add_12(ld12,&tmp);
}
/* normalize mantissa -- first shift word by word */
while (*UL_HI_12(ld12) == 0) {
*UL_HI_12(ld12) = *UL_MED_12(ld12) >> 16;
*UL_MED_12(ld12) = *UL_MED_12(ld12) << 16 | *UL_LO_12(ld12) >> 16;
(*UL_LO_12(ld12)) <<= 16;
expn -= 16;
}
while ((*UL_HI_12(ld12) & 0x8000) == 0) {
__shl_12(ld12);
expn--;
}
*U_EXP_12(ld12) = expn;
}
#define STRCPY strcpy
#define PUT_ZERO_FOS(fos) \
fos->exp = 1, \
fos->sign = ' ', \
fos->ManLen = 1, \
fos->man[0] = '0',\
fos->man[1] = 0;
#define SNAN_STR "1#SNAN"
#define SNAN_STR_LEN 6
#define QNAN_STR "1#QNAN"
#define QNAN_STR_LEN 6
#define INF_STR "1#INF"
#define INF_STR_LEN 5
#define IND_STR "1#IND"
#define IND_STR_LEN 5
/***
char * _uldtoa (_ULDOUBLE *px,
* int maxchars,
* char *ldtext)
*
*
*Purpose:
* Return pointer to filled in string "ldtext" for
* a given _UDOUBLE ponter px
* with a maximum character width of maxchars
*
*Entry:
* _ULDOUBLE * px: a pointer to the long double to be converted into a string
* int maxchars: number of digits allowed in the output format.
*
* (default is 'e' format)
*
* char * ldtext: a pointer to the output string
*
*Exit:
* returns pointer to the output string
*
*Exceptions:
*
*******************************************************************************/
char * _uldtoa (_ULDOUBLE *px, int maxchars, char *ldtext)
{
char in_str [250];
char in_str2 [250];
char cExp[20];
FOS foss;
char * lpszMan;
char * lpIndx;
int nErr;
int len1, len2;
maxchars -= 9; /* sign, dot, E+0001 */
nErr = $I10_OUTPUT (*px, maxchars, 0, &foss);
lpszMan = foss.man;
ldtext[0] = foss.sign;
ldtext[1] = *lpszMan;
ldtext[2] = '.';
ldtext[3] = '\0';
maxchars += 2; /* sign, dot */
lpszMan++;
strcat (ldtext, lpszMan);
len1 = strlen (ldtext); // for 'e'
strcpy (cExp, "e");
foss.exp -= 1; /* Adjust for the shift decimal shift above */
_itoa (foss.exp, in_str, 10);
if (foss.exp < 0) {
strcat (cExp, "-");
strcpy (in_str2, &in_str[1]);
strcpy (in_str, in_str2);
while (strlen(in_str) < 4) {
strcpy (in_str2, in_str);
strcpy (in_str,"0");
strcat (in_str,in_str2);
}
} else {
while (strlen(in_str) < 4) {
strcpy (in_str2, in_str);
strcpy (in_str,"0");
strcat (in_str,in_str2);
}
}
if (foss.exp >= 0) {
strcat (cExp, "+");
}
strcat (cExp, in_str);
len2 = strlen (cExp);
if (len1 == maxchars) {
;
}
else if (len1 < maxchars) {
do {
strcat (ldtext,"0");
len1++;
} while (len1 < maxchars);
}
else {
lpIndx = &ldtext[len1 - 1]; // point to last char and round
do {
*lpIndx = '\0';
lpIndx--;
len1--; //NOTENOTE v-griffk we really need to round
} while (len1 > maxchars);
}
strcat (ldtext, cExp);
return ldtext;
}
/***
*int _$i10_output(_ULDOUBLE ld,
* int ndigits,
* unsigned output_flags,
* FOS *fos) - output conversion of a 10-byte _ULDOUBLE
*
*Purpose:
* Fill in a FOS structure for a given _ULDOUBLE
*
*Entry:
* _ULDOUBLE ld: The long double to be converted into a string
* int ndigits: number of digits allowed in the output format.
* unsigned output_flags: The following flags can be used:
* SO_FFORMAT: Indicates 'f' format
* (default is 'e' format)
* FOS *fos: the structure that i10_output will fill in
*
*Exit:
* modifies *fos
* return 1 if original number was ok, 0 otherwise (infinity, NaN, etc)
*
*Exceptions:
*
*******************************************************************************/
int $I10_OUTPUT(_ULDOUBLE ld, int ndigits,
unsigned output_flags, FOS *fos)
{
u_short expn;
u_long manhi,manlo;
u_short sign;
/* useful constants (see algorithm explanation below) */
u_short const log2hi = 0x4d10;
u_short const log2lo = 0x4d;
u_short const log4hi = 0x9a;
u_long const c = 0x134312f4;
#if defined(L_END)
_ULDBL12 ld12_one_tenth = {
{0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcc,0xfb,0x3f}
};
#elif defined(B_END)
_ULDBL12 ld12_one_tenth = {
{0x3f,0xfb,0xcc,0xcc,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcc,0xcc,0xcc}
};
#endif
_ULDBL12 ld12; /* space for a 12-byte long double */
_ULDBL12 tmp12;
u_short hh,ll; /* the bytes of the exponent grouped in 2 words*/
u_short mm; /* the two MSBytes of the mantissa */
s_long r; /* the corresponding power of 10 */
s_short ir; /* ir = floor(r) */
int retval = 1; /* assume valid number */
char round; /* an additional character at the end of the string */
char *p;
int i;
int ub_exp;
int digcount;
/* grab the components of the long double */
expn = *U_EXP_LD(&ld);
manhi = *UL_MANHI_LD(&ld);
manlo = *UL_MANLO_LD(&ld);
sign = expn & MSB_USHORT;
expn &= 0x7fff;
if (sign)
fos->sign = '-';
else
fos->sign = ' ';
if (expn==0 && manhi==0 && manlo==0) {
PUT_ZERO_FOS(fos);
return 1;
}
if (expn == 0x7fff) {
fos->exp = 1; /* set a positive exponent for proper output */
/* check for special cases */
if (_IS_MAN_SNAN(sign, manhi, manlo)) {
/* signaling NAN */
STRCPY(fos->man,SNAN_STR);
fos->ManLen = SNAN_STR_LEN;
retval = 0;
}
else if (_IS_MAN_IND(sign, manhi, manlo)) {
/* indefinite */
STRCPY(fos->man,IND_STR);
fos->ManLen = IND_STR_LEN;
retval = 0;
}
else if (_IS_MAN_INF(sign, manhi, manlo)) {
/* infinity */
STRCPY(fos->man,INF_STR);
fos->ManLen = INF_STR_LEN;
retval = 0;
}
else {
/* quiet NAN */
STRCPY(fos->man,QNAN_STR);
fos->ManLen = QNAN_STR_LEN;
retval = 0;
}
}
else {
/*
* Algorithm for the decoding of a valid real number x
*
* In the following INT(r) is the largest integer less than or
* equal to r (i.e. r rounded toward -infinity). We want a result
* r equal to 1 + log(x), because then x = mantissa
* * 10^(INT(r)) so that .1 <= mantissa < 1. Unfortunately,
* we cannot compute s exactly so we must alter the procedure
* slightly. We will instead compute an estimate r of 1 +
* log(x) which is always low. This will either result
* in the correctly normalized number on the top of the stack
* or perhaps a number which is a factor of 10 too large. We
* will then check to see that if x is larger than one
* and if so multiply x by 1/10.
*
* We will use a low precision (fixed point 24 bit) estimate
* of of 1 + log base 10 of x. We have approximately .mm
* * 2^hhll on the top of the stack where m, h, and l represent
* hex digits, mm represents the high 2 hex digits of the
* mantissa, hh represents the high 2 hex digits of the exponent,
* and ll represents the low 2 hex digits of the exponent. Since
* .mm is a truncated representation of the mantissa, using it
* in this monotonically increasing polynomial approximation
* of the logarithm will naturally give a low result. Let's
* derive a formula for a lower bound r on 1 + log(x):
*
* .4D104D42H < log(2)=.30102999...(base 10) < .4D104D43H
* .9A20H < log(4)=.60205999...(base 10) < .9A21H
*
* 1/2 <= .mm < 1
* ==> log(.mm) >= .mm * log(4) - log(4)
*
* Substituting in truncated hex constants in the formula above
* gives r = 1 + .4D104DH * hhll. + .9AH * .mm - .9A21H. Now
* multiplication of hex digits 5 and 6 of log(2) by ll has an
* insignificant effect on the first 24 bits of the result so
* it will not be calculated. This gives the expression r =
* 1 + .4D10H * hhll. + .4DH * .hh + .9A * .mm - .9A21H.
* Finally we must add terms to our formula to subtract out the
* effect of the exponent bias. We obtain the following formula:
*
* (implied decimal point)
* < >.< >
* |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|
* |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|
* + < 1 >
* + < .4D10H * hhll. >
* + < .00004DH * hh00. >
* + < .9AH * .mm >
* - < .9A21H >
* - < .4D10H * 3FFEH >
* - < .00004DH * 3F00H >
*
* ==> r = .4D10H * hhll. + .4DH * .hh + .9AH * .mm - 1343.12F4H
*
* The difference between the lower bound r and the upper bound
* s is calculated as follows:
*
* .937EH < 1/ln(10)-log(1/ln(4))=.57614993...(base 10) < .937FH
*
* 1/2 <= .mm < 1
* ==> log(.mm) <= .mm * log(4) - [1/ln(10) - log(1/ln(4))]
*
* so tenatively s = r + log(4) - [1/ln(10) - log(1/ln(4))],
* but we must also add in terms to ensure we will have an upper
* bound even after the truncation of various values. Because
* log(2) * hh00. is truncated to .4D104DH * hh00. we must
* add .0043H, because log(2) * ll. is truncated to .4D10H *
* ll. we must add .0005H, because <mantissa> * log(4) is
* truncated to .mm * .9AH we must add .009AH and .0021H.
*
* Thus s = r - .937EH + .9A21H + .0043H + .0005H + .009AH + .0021H
* = r + .07A6H
* ==> s = .4D10H * hhll. + .4DH * .hh + .9AH * .mm - 1343.0B4EH
*
* r is equal to 1 + log(x) more than (10000H - 7A6H) /
* 10000H = 97% of the time.
*
* In the above formula, a u_long is use to accomodate r, and
* there is an implied decimal point in the middle.
*/
hh = expn >> 8;
ll = expn & (u_short)0xff;
mm = (u_short) (manhi >> 24);
r = (s_long)log2hi*(s_long)expn + log2lo*hh + log4hi*mm - c;
ir = (s_short)(r >> 16);
/*
*
* We stated that we wanted to normalize x so that
*
* .1 <= x < 1
*
* This was a slight oversimplification. Actually we want a
* number which when rounded to 16 significant digits is in the
* desired range. To do this we must normalize x so that
*
* .1 - 5*10^(-18) <= x < 1 - 5*10^(-17)
*
* and then round.
*
* If we had f = INT(1+log(x)) we could multiply by 10^(-f)
* to get x into the desired range. We do not quite have
* f but we do have INT(r) from the last step which is equal
* to f 97% of the time and 1 less than f the rest of the time.
* We can multiply by 10^-[INT(r)] and if the result is greater
* than 1 - 5*10^(-17) we can then multiply by 1/10. This final
* result will lie in the proper range.
*/
/* convert _ULDOUBLE to _ULDBL12) */
*U_EXP_12(&ld12) = expn;
*UL_MANHI_12(&ld12) = manhi;
*UL_MANLO_12(&ld12) = manlo;
*U_XT_12(&ld12) = 0;
/* multiply by 10^(-ir) */
__multtenpow12(&ld12,-ir,1);
/* if ld12 >= 1.0 then divide by 10.0 */
if (*U_EXP_12(&ld12) >= 0x3fff) {
ir++;
__ld12mul(&ld12,&ld12_one_tenth);
}
fos->exp = ir;
if (output_flags & SO_FFORMAT){
/* 'f' format, add exponent to ndigits */
ndigits += ir;
if (ndigits <= 0) {
/* return 0 */
PUT_ZERO_FOS(fos);
return 1;
}
}
if (ndigits > MAX_MAN_DIGITS)
ndigits = MAX_MAN_DIGITS;
ub_exp = *U_EXP_12(&ld12) - 0x3ffe; /* unbias exponent */
*U_EXP_12(&ld12) = 0;
/*
* Now the mantissa has to be converted to fixed point.
* Then we will use the MSB of ld12 for generating
* the decimal digits. The next 11 bytes will hold
* the mantissa (after it has been converted to
* fixed point).
*/
for (i=0;i<8;i++)
__shl_12(&ld12); /* make space for an extra byte,
in case we shift right later */
if (ub_exp < 0) {
int shift_count = (-ub_exp) & 0xff;
for (;shift_count>0;shift_count--)
__shr_12(&ld12);
}
p = fos->man;
for(digcount=ndigits+1;digcount>0;digcount--) {
tmp12 = ld12;
__shl_12(&ld12);
__shl_12(&ld12);
__add_12(&ld12,&tmp12);
__shl_12(&ld12); /* ld12 *= 10 */
/* Now we have the first decimal digit in the msbyte of exponent */
*p++ = (char) (*UCHAR_12(&ld12,11) + '0');
*UCHAR_12(&ld12,11) = 0;
}
round = *(--p);
p--; /* p points now to the last character of the string
excluding the rounding digit */
if (round >= '5') {
/* look for a non-9 digit starting from the end of string */
for (;p>=fos->man && *p=='9';p--) {
*p = '0';
}
if (p < fos->man){
p++;
fos->exp ++;
}
(*p)++;
}
else {
/* remove zeros */
for (;p>=fos->man && *p=='0';p--);
if (p < fos->man) {
/* return 0 */
PUT_ZERO_FOS(fos);
return 1;
}
}
fos->ManLen = (char) (p - fos->man + 1);
fos->man[fos->ManLen] = '\0';
}
return retval;
}
/***
*strgtold.c - conversion of a string into a long double
*
* Copyright (c) 1991-1991, Microsoft Corporation. All rights reserved.
*
*Purpose: convert a fp constant into a 10 byte long double (IEEE format)
*
*Revision History:
* 7-17-91 GDP Initial version (ported from assembly)
* 4-03-92 GDP Preserve sign of -0
* 4-30-92 GDP Now returns _ULDBL12 instead of _ULDOUBLE
* 05-26-92 GWK Windbg srcs
*
*******************************************************************************/
/* local macros */
#define ISNZDIGIT(x) ((x)>='1' && (x)<='9' )
//NOTENOTE the following takes the place of the isdigit() macro
// which does not work for a yet to be determined reason
#define ISADIGIT(x) ((x)>='0' && (x)<='9' )
#define ISWHITE(x) ((x)==' ' || (x)=='\t' || (x)=='\n' || (x)=='\r' )
/****
*unsigned int __strgtold( _ULDBL12 *pld12,
* char * * pEndPtr,
* char * str,
* int Mult12 )
*
*Purpose:
* converts a character string into a long double
*
*Entry:
* pld12 - pointer to the _ULDBL12 where the result should go.
* pEndStr - pointer to a far pointer that will be set to the end of string.
* str - pointer to the string to be converted.
* Mult12 - set to non zero if the _ULDBL12 multiply should be used instead of
* the long double mulitiply.
*
*Exit:
* Returns the SLD_* flags or'ed together.
*
*Uses:
*
*Exceptions:
*
********************************************************************************/
unsigned int
__strgtold12(_ULDBL12 *pld12,
char * *p_end_ptr,
char *str,
int mult12)
{
typedef enum {
S_INIT, /* initial state */
S_EAT0L, /* eat 0's at the left of mantissa */
S_SIGNM, /* just read sign of mantissa */
S_GETL, /* get integer part of mantissa */
S_GETR, /* get decimal part of mantissa */
S_POINT, /* just found decimal point */
S_E, /* just found 'E', or 'e', etc */
S_SIGNE, /* just read sign of exponent */
S_EAT0E, /* eat 0's at the left of exponent */
S_GETE, /* get exponent */
S_END /* final state */
} state_t;
/* this will accomodate the digits of the mantissa in BCD form*/
static char buf[LD_MAX_MAN_LEN1];
char *manp = buf;
/* a temporary _ULDBL12 */
_ULDBL12 tmpld12;
u_short man_sign = 0; /* to be ORed with result */
int exp_sign = 1; /* default sign of exponent (values: +1 or -1)*/
/* number of decimal significant mantissa digits so far*/
unsigned manlen = 0;
int found_digit = 0;
int overflow = 0;
int underflow = 0;
int pow = 0;
int exp_adj = 0; /* exponent adjustment */
u_long ul0,ul1;
u_short u,uexp;
unsigned int result_flags = 0;
state_t state = S_INIT;
char c; /* the current input symbol */
char *p; /* a pointer to the next input symbol */
char *savedp;
for(savedp=p=str;ISWHITE(*p);p++); /* eat up white space */
while (state != S_END) {
c = *p++;
switch (state) {
case S_INIT:
if (ISNZDIGIT(c)) {
state = S_GETL;
p--;
}
else
switch (c) {
case '0':
state = S_EAT0L;
break;
case '+':
state = S_SIGNM;
man_sign = 0x0000;
break;
case '-':
state = S_SIGNM;
man_sign = 0x8000;
break;
case '.':
state = S_POINT;
break;
default:
state = S_END;
p--;
break;
}
break;
case S_EAT0L:
found_digit = 1;
if (ISNZDIGIT(c)) {
state = S_GETL;
p--;
}
else
switch (c) {
case '0':
state = S_EAT0L;
break;
case 'E':
case 'e':
case 'D':
case 'd':
state = S_E;
break;
case '.':
state = S_GETR;
break;
default:
state = S_END;
p--;
}
break;
case S_SIGNM:
if (ISNZDIGIT(c)) {
state = S_GETL;
p--;
}
else
switch (c) {
case '0':
state = S_EAT0L;
break;
case '.':
state = S_POINT;
break;
default:
state = S_END;
p = savedp;
}
break;
case S_GETL:
found_digit = 1;
for (;ISADIGIT(c);c=*p++) {
if (manlen < LD_MAX_MAN_LEN+1){
manlen++;
*manp++ = c - (char)'0';
}
else
exp_adj++;
}
switch (c) {
case '.':
state = S_GETR;
break;
case 'E':
case 'e':
case 'D':
case 'd':
state = S_E;
break;
default:
state = S_END;
p--;
}
break;
case S_GETR:
found_digit = 1;
if (manlen == 0)
for (;c=='0';c=*p++)
exp_adj--;
for(;ISADIGIT(c);c=*p++){
if (manlen < LD_MAX_MAN_LEN+1){
manlen++;
*manp++ = c - (char)'0';
exp_adj--;
}
}
switch (c){
case 'E':
case 'e':
case 'D':
case 'd':
state = S_E;
break;
default:
state = S_END;
p--;
}
break;
case S_POINT:
if (ISADIGIT(c)){
state = S_GETR;
p--;
}
else{
state = S_END;
p = savedp;
}
break;
case S_E:
savedp = p-2; /* savedp points to 'E' */
if (ISNZDIGIT(c)){
state = S_GETE;
p--;
}
else
switch (c){
case '0':
state = S_EAT0E;
break;
case '-':
state = S_SIGNE;
exp_sign = -1;
break;
case '+':
state = S_SIGNE;
break;
default:
state = S_END;
p = savedp;
}
break;
case S_EAT0E:
for(;c=='0';c=*p++);
if (ISNZDIGIT(c)){
state = S_GETE;
p--;
}
else {
state = S_END;
p--;
}
break;
case S_SIGNE:
if (ISNZDIGIT(c)){
state = S_GETE;
p--;
}
else
switch (c){
case '0':
state = S_EAT0E;
break;
default:
state = S_END;
p = savedp;
}
break;
case S_GETE:
{
long longpow=0; /* TMAX10*10 should fit in a long */
for(;ISADIGIT(c);c=*p++){
longpow = longpow*10 + (c - '0');
if (longpow > TMAX10){
longpow = TMAX10+1; /* will force overflow */
break;
}
}
pow = (int)longpow;
}
for(;ISADIGIT(c);c=*p++); /* eat up remaining digits */
state = S_END;
p--;
break;
} /* switch */
} /* while */
*p_end_ptr = p; /* set end pointer */
/*
* Compute result
*/
if (found_digit && !overflow && !underflow) {
if (manlen>LD_MAX_MAN_LEN){
if (buf[LD_MAX_MAN_LEN-1]>=5) {
/*
* Round mantissa to MAX_MAN_LEN digits
* It's ok to round 9 to 0ah
*/
buf[LD_MAX_MAN_LEN-1]++;
}
manlen = LD_MAX_MAN_LEN;
manp--;
exp_adj++;
}
if (manlen>0) {
/*
* Remove trailing zero's from mantissa
*/
for(manp--;*manp==0;manp--) {
/* there is at least one non-zero digit */
manlen--;
exp_adj++;
}
__mtold12(buf,manlen,&tmpld12);
if (exp_sign < 0)
pow = -pow;
pow += exp_adj;
if (pow > TMAX10)
overflow = 1;
else if (pow < TMIN10)
underflow = 1;
else {
__multtenpow12(&tmpld12,pow,mult12);
u = *U_XT_12(&tmpld12);
ul0 =*UL_MANLO_12(&tmpld12);
ul1 = *UL_MANHI_12(&tmpld12);
uexp = *U_EXP_12(&tmpld12);
}
}
else {
/* manlen == 0, so return 0 */
u = (u_short)0;
ul0 = ul1 = uexp = 0;
}
}
if (!found_digit) {
/* return 0 */
u = (u_short)0;
ul0 = ul1 = uexp = 0;
result_flags |= SLD_NODIGITS;
}
else if (overflow) {
/* return +inf or -inf */
uexp = (u_short)0x7fff;
ul1 = 0x80000000;
ul0 = 0;
u = (u_short)0;
result_flags |= SLD_OVERFLOW;
}
else if (underflow) {
/* return 0 */
u = (u_short)0;
ul0 = ul1 = uexp = 0;
result_flags |= SLD_UNDERFLOW;
}
/*
* Assemble result
*/
*U_XT_12(pld12) = u;
*UL_MANLO_12(pld12) = ul0;
*UL_MANHI_12(pld12) = ul1;
*U_EXP_12(pld12) = uexp | man_sign;
return result_flags;
}
/***
* intrncvt.c - internal floating point conversions
*
* Copyright (c) 1992-1992, Microsoft Corporation. All rights reserved.
*
*Purpose:
* All fp string conversion routines use the same core conversion code
* that converts strings into an internal long double representation
* with an 80-bit mantissa field. The mantissa is represented
* as an array (man) of 32-bit unsigned longs, with man[0] holding
* the high order 32 bits of the mantissa. The binary point is assumed
* to be between the MSB and MSB-1 of man[0].
*
* Bits are counted as follows:
*
*
* +-- binary point
* |
* v MSB LSB
* ---------------- ------------------ --------------------
* |0 1 .... 31| | 32 33 ... 63| | 64 65 ... 95|
* ---------------- ------------------ --------------------
*
* man[0] man[1] man[2]
*
* This file provides the final conversion routines from this internal
* form to the single, double, or long double precision floating point
* format.
*
* All these functions do not handle NaNs (it is not necessary)
*
*
*Revision History:
* 04-29-92 GDP written
* 05-26-92 GWK Windbg srcs
*
*******************************************************************************/
#define INTRNMAN_LEN 3 /* internal mantissa length in int's */
//
// internal mantissaa representation
// for string conversion routines
//
typedef u_long *intrnman;
typedef struct {
int max_exp; // maximum base 2 exponent (reserved for special values)
int min_exp; // minimum base 2 exponent (reserved for denormals)
int precision; // bits of precision carried in the mantissa
int exp_width; // number of bits for exponent
int format_width; // format width in bits
int bias; // exponent bias
} FpFormatDescriptor;
static FpFormatDescriptor
DoubleFormat = {
0x7ff - 0x3ff, // 1024, maximum base 2 exponent (reserved for special values)
0x0 - 0x3ff, // -1023, minimum base 2 exponent (reserved for denormals)
53, // bits of precision carried in the mantissa
11, // number of bits for exponent
64, // format width in bits
0x3ff, // exponent bias
};
static FpFormatDescriptor
FloatFormat = {
0xff - 0x7f, // 128, maximum base 2 exponent (reserved for special values)
0x0 - 0x7f, // -127, minimum base 2 exponent (reserved for denormals)
24, // bits of precision carried in the mantissa
8, // number of bits for exponent
32, // format width in bits
0x7f, // exponent bias
};
//
// function prototypes
//
int _RoundMan (intrnman man, int nbit);
int _ZeroTail (intrnman man, int nbit);
int _IncMan (intrnman man, int nbit);
void _CopyMan (intrnman dest, intrnman src);
void _CopyMan (intrnman dest, intrnman src);
void _FillZeroMan(intrnman man);
void _Shrman (intrnman man, int n);
INTRNCVT_STATUS _ld12cvt(_ULDBL12 *pld12, void *d, FpFormatDescriptor *format);
/***
* _ZeroTail - check if a mantissa ends in 0's
*
*Purpose:
* Return TRUE if all mantissa bits after nbit (including nbit) are 0,
* otherwise return FALSE
*
*
*Entry:
* man: mantissa
* nbit: order of bit where the tail begins
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
int _ZeroTail (intrnman man, int nbit)
{
int nl = nbit / 32;
int nb = 31 - nbit % 32;
//
// |<---- tail to be checked --->
//
// -- ------------------------ ----
// |... | | ... |
// -- ------------------------ ----
// ^ ^ ^
// | | |<----nb----->
// man nl nbit
//
u_long bitmask = ~(MAX_ULONG << nb);
if (man[nl] & bitmask)
return 0;
nl++;
for (;nl < INTRNMAN_LEN; nl++)
if (man[nl])
return 0;
return 1;
}
/***
* _IncMan - increment mantissa
*
*Purpose:
*
*
*Entry:
* man: mantissa in internal long form
* nbit: order of bit that specifies the end of the part to be incremented
*
*Exit:
* returns 1 on overflow, 0 otherwise
*
*Exceptions:
*
*******************************************************************************/
int _IncMan (intrnman man, int nbit)
{
int nl = nbit / 32;
int nb = 31 - nbit % 32;
//
// |<--- part to be incremented -->|
//
// -- --------------------------- ----
// |... | | ... |
// -- --------------------------- ----
// ^ ^ ^
// | | |<--nb-->
// man nl nbit
//
u_long one = (u_long) 1 << nb;
int carry;
carry = __addl(man[nl], one, &man[nl]);
nl--;
for (; nl >= 0 && carry; nl--) {
carry = (u_long) __addl(man[nl], (u_long) 1, &man[nl]);
}
return carry;
}
/***
* _RoundMan - round mantissa
*
*Purpose:
* round mantissa to nbit precision
*
*
*Entry:
* man: mantissa in internal form
* precision: number of bits to be kept after rounding
*
*Exit:
* returns 1 on overflow, 0 otherwise
*
*Exceptions:
*
*******************************************************************************/
int _RoundMan (intrnman man, int precision)
{
int i,rndbit,nl,nb;
u_long rndmask;
int nbit;
int retval = 0;
//
// The order of the n'th bit is n-1, since the first bit is bit 0
// therefore decrement precision to get the order of the last bit
// to be kept
//
nbit = precision - 1;
rndbit = nbit+1;
nl = rndbit / 32;
nb = 31 - rndbit % 32;
//
// Get value of round bit
//
rndmask = (u_long)1 << nb;
if ((man[nl] & rndmask) &&
!_ZeroTail(man, rndbit+1)) {
//
// round up
//
retval = _IncMan(man, nbit);
}
//
// fill rest of mantissa with zeroes
//
man[nl] &= MAX_ULONG << nb;
for(i=nl+1; i<INTRNMAN_LEN; i++) {
man[i] = (u_long)0;
}
return retval;
}
/***
* _CopyMan - copy mantissa
*
*Purpose:
* copy src to dest
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _CopyMan (intrnman dest, intrnman src)
{
u_long *p, *q;
int i;
p = src;
q = dest;
for (i=0; i < INTRNMAN_LEN; i++) {
*q++ = *p++;
}
}
/***
* _FillZeroMan - fill mantissa with zeroes
*
*Purpose:
*
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _FillZeroMan(intrnman man)
{
int i;
for (i=0; i < INTRNMAN_LEN; i++)
man[i] = (u_long)0;
}
/***
* _IsZeroMan - check if mantissa is zero
*
*Purpose:
*
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
int _IsZeroMan(intrnman man)
{
int i;
for (i=0; i < INTRNMAN_LEN; i++)
if (man[i])
return 0;
return 1;
}
/***
* _ShrMan - shift mantissa to the right
*
*Purpose:
* shift man by n bits to the right
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _ShrMan (intrnman man, int n)
{
int i, n1, n2, mask;
int carry_from_left;
//
// declare this as volatile in order to work around a C8
// optimization bug
//
volatile int carry_to_right;
n1 = n / 32;
n2 = n % 32;
mask = ~(MAX_ULONG << n2);
//
// first deal with shifts by less than 32 bits
//
carry_from_left = 0;
for (i=0; i<INTRNMAN_LEN; i++) {
carry_to_right = man[i] & mask;
man[i] >>= n2;
man[i] |= carry_from_left;
carry_from_left = carry_to_right << (32 - n2);
}
//
// now shift whole 32-bit ints
//
for (i=INTRNMAN_LEN-1; i>=0; i--) {
if (i >= n1) {
man[i] = man[i-n1];
}
else {
man[i] = 0;
}
}
}
/***
* _ld12tocvt - _ULDBL12 floating point conversion
*
*Purpose:
* convert a internal _LBL12 structure into an IEEE floating point
* representation
*
*
*Entry:
* pld12: pointer to the _ULDBL12
* format: pointer to the format descriptor structure
*
*Exit:
* *d contains the IEEE representation
* returns the INTRNCVT_STATUS
*
*Exceptions:
*
*******************************************************************************/
INTRNCVT_STATUS _ld12cvt(_ULDBL12 *pld12, void *d, FpFormatDescriptor *format)
{
u_long man[INTRNMAN_LEN];
u_long saved_man[INTRNMAN_LEN];
u_long msw;
unsigned int bexp; // biased exponent
int exp_shift;
int exponent, sign;
INTRNCVT_STATUS retval;
exponent = (*U_EXP_12(pld12) & 0x7fff) - 0x3fff; // unbias exponent
sign = *U_EXP_12(pld12) & 0x8000;
//
// bexp is the final biased value of the exponent to be used
// Each of the following blocks should provide appropriate
// values for man, bexp and retval. The mantissa is also
// shifted to the right, leaving space for the exponent
// and sign to be inserted
//
if (exponent == 0 - 0x3fff) {
// either a denormal or zero
bexp = 0;
_FillZeroMan(man);
if (ISZERO_12(pld12)) {
retval = INTRNCVT_OK;
}
else {
// denormal has been flushed to zero
retval = INTRNCVT_UNDERFLOW;
}
}
else {
man[0] = *UL_MANHI_12(pld12);
man[1] = *UL_MANLO_12(pld12);
man[2] = *U_XT_12(pld12) << 16;
// save mantissa in case it needs to be rounded again
// at a different point (e.g., if the result is a denormal)
_CopyMan(saved_man, man);
if (_RoundMan(man, format->precision)) {
exponent ++;
}
if (exponent < format->min_exp - format->precision ) {
//
// underflow that produces a zero
//
_FillZeroMan(man);
bexp = 0;
retval = INTRNCVT_UNDERFLOW;
}
else if (exponent <= format->min_exp) {
//
// underflow that produces a denormal
//
//
// The (unbiased) exponent will be MIN_EXP
// Find out how much the mantissa should be shifted
// One shift is done implicitly by moving the
// binary point one bit to the left, i.e.,
// we treat the mantissa as .ddddd instead of d.dddd
// (where d is a binary digit)
int shift = format->min_exp - exponent;
// The mantissa should be rounded again, so it
// has to be restored
_CopyMan(man,saved_man);
_ShrMan(man, shift);
_RoundMan(man, format->precision); // need not check for carry
// make room for the exponent + sign
_ShrMan(man, format->exp_width + 1);
bexp = 0;
retval = INTRNCVT_UNDERFLOW;
}
else if (exponent >= format->max_exp) {
//
// overflow, return infinity
//
_FillZeroMan(man);
man[0] |= (1 << 31); // set MSB
// make room for the exponent + sign
_ShrMan(man, (format->exp_width + 1) - 1);
bexp = format->max_exp + format->bias;
retval = INTRNCVT_OVERFLOW;
}
else {
//
// valid, normalized result
//
bexp = exponent + format->bias;
// clear implied bit
man[0] &= (~( 1 << 31));
//
// shift right to make room for exponent + sign
//
_ShrMan(man, (format->exp_width + 1) - 1);
retval = INTRNCVT_OK;
}
}
exp_shift = 32 - (format->exp_width + 1);
msw = man[0] |
(bexp << exp_shift) |
(sign ? 1<<31 : 0);
if (format->format_width == 64) {
*UL_HI_D(d) = msw;
*UL_LO_D(d) = man[1];
}
else if (format->format_width == 32) {
*(u_long *)d = msw;
}
return retval;
}
/***
* _ld12tod - convert _ULDBL12 to double
*
*Purpose:
*
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
INTRNCVT_STATUS _ld12tod(_ULDBL12 *pld12, UDOUBLE *d)
{
return _ld12cvt(pld12, d, &DoubleFormat);
}
/***
* _ld12tof - convert _ULDBL12 to float
*
*Purpose:
*
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
INTRNCVT_STATUS _ld12tof(_ULDBL12 *pld12, FLOAT *f)
{
return _ld12cvt(pld12, f, &FloatFormat);
}
/***
* _ld12told - convert _ULDBL12 to 80 bit long double
*
*Purpose:
*
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _ld12told(_ULDBL12 *pld12, _ULDOUBLE *pld)
{
//
// This implementation is based on the fact that the _ULDBL12 format is
// identical to the long double and has 2 extra bytes of mantissa
//
u_short exp, sign;
u_long man[INTRNMAN_LEN];
exp = *U_EXP_12(pld12) & (u_short)0x7fff;
sign = *U_EXP_12(pld12) & (u_short)0x8000;
man[0] = *UL_MANHI_12(pld12);
man[1] = *UL_MANLO_12(pld12);
man[2] = *U_XT_12(pld12) << 16;
if (_RoundMan(man, 64))
exp ++;
*UL_MANHI_LD(pld) = man[0];
*UL_MANLO_LD(pld) = man[1];
*U_EXP_LD(pld) = sign | exp;
}
void _atodbl(UDOUBLE *d, char *str)
{
char *EndPtr;
_ULDBL12 ld12;
__strgtold12(&ld12, &EndPtr, str, 0 );
_ld12tod(&ld12, d);
}
void _atoldbl(_ULDOUBLE *ld, char *str)
{
char *EndPtr;
_ULDBL12 ld12;
__strgtold12(&ld12, &EndPtr, str, 0 );
_ld12told(&ld12, ld);
}
void _atoflt(FLOAT *f, char *str)
{
char *EndPtr;
_ULDBL12 ld12;
__strgtold12(&ld12, &EndPtr, str, 0 );
_ld12tof(&ld12, f);
}
double
Float82ToDouble(const FLOAT128* FpReg82)
{
double f = 0.0;
FLOAT82_FORMAT* f82 = (FLOAT82_FORMAT*)FpReg82;
ULONG64 mant = f82->significand;
if (mant)
{
int exp = (f82->exponent ? (f82->exponent - 0xffff) : -0x3ffe) - 63;
// try to minimize abs(iExp)
while (exp > 0 && mant && !(mant & (ULONG64(1)<<63)))
{
mant <<= 1;
--exp;
}
while (exp < 0 && mant && !(mant & 1))
{
mant >>= 1;
++exp;
}
f = ldexp(double(mant), exp);
if (f82->sign)
{
f = -f;
}
}
return f;
}
void
DoubleToFloat82(double f, FLOAT128* FpReg82)
{
ZeroMemory(FpReg82, sizeof(FLOAT128));
FLOAT82_FORMAT* f82 = (FLOAT82_FORMAT*)FpReg82;
// Normalize
int exp;
f = frexp(f, &exp);
if (f < 0)
{
f82->sign = 1;
f = -f;
}
// shift fraction into integer part
ULONG64 mant;
while (double(mant = ULONG64(f)) < f)
{
f = f * 2.0;
--exp;
}
f82->exponent = exp + 0xffff + 0x3f;
f82->significand = mant;
}