singrdk/base/Kernel/Native/Number.cpp

823 lines
33 KiB
C++
Raw Normal View History

2008-03-05 09:52:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Number.cpp
//
2008-11-17 18:29:00 -05:00
// Note: Kernel & Process
2008-03-05 09:52:00 -05:00
//
#include "hal.h"
2008-11-17 18:29:00 -05:00
//////////////////////////////////////////////////////////////////////////////
//
extern "C" int _fltused = 0x9875;
2008-03-05 09:52:00 -05:00
//////////////////////////////////////////////////////////////////////////////
//
#define LITTLE_ENDIAN
#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC) || defined(_M_IA64)
#define REQUIRES_UNALIGNED_FLAG
#endif
//////////////////////////////////////////////////////////////////////////////
//
static const int32 SCALE_NAN = (int32)0x80000000;
static const int32 SCALE_INF = 0x7FFFFFFF;
// Currently our string conversion routines do not conform to the special
// requirements of the IEEE standard for floating point conversions.
// We do this to avoid IEEE exceptions.
#pragma pack(4)
typedef struct {
uint8 ld12[12];
} _LDBL12;
#pragma pack()
#define PTR_12(x) ((uint8 *)(&(x)->ld12))
#define MAX_USHORT ((uint16)0xffff)
#define MSB_USHORT ((uint16)0x8000)
#define MAX_ULONG ((uint32)0xffffffff)
#define MSB_ULONG ((uint32)0x80000000)
#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
#define _IS_MAN_INF(signbit, manhi, manlo) ((manhi)==MSB_ULONG && (manlo)==0x0 )
#if defined (LITTLE_ENDIAN)
// Manipulation of a 12-byte long double number (an ordinary
// 10-byte long double plus two extra bytes of mantissa).
//
// byte layout:
//
// +--+--+--+--+--+--+--+--+--+--+--+--+
// |XT:2 | MANLO:4 | MANHI:4 |EXP:2|
// +--+--+--+--+--+--+--+--+--+--+--+--+
// | UL_LO:4 | UL_MED:4 | UL_HI:4 |
// +--+--+--+--+--+--+--+--+--+--+--+--+
//
#define U_EXP_12(p) ((uint16 *)(PTR_12(p)+10)) // exponent/sign
#if !defined(REQUIRES_UNALIGNED_FLAG)
#define UL_MANHI_12(p) ((uint32 *)(PTR_12(p)+6)) // 4 hi-order bytes of ord mantissa
#define UL_MANLO_12(p) ((uint32 *)(PTR_12(p)+2)) // 4 lo-order bytes of ord mantissa
#else
#define UL_MANHI_12(p) ((uint32 __unaligned *) (PTR_12(p)+6) )
#define UL_MANLO_12(p) ((uint32 __unaligned *) (PTR_12(p)+2) )
#endif // defined(REQUIRES_UNALIGNED_FLAG)
#define U_XT_12(p) ((uint16 *)PTR_12(p)) // 2 extra-lo bytes of mantissa
#define UL_LO_12(p) ((uint32 *)PTR_12(p)) // 4 lo-order bytes of 12-byte value
#define UL_MED_12(p) ((uint32 *)(PTR_12(p)+4)) // 4 mid-order bytes of 12-byte value
#define UL_HI_12(p) ((uint32 *)(PTR_12(p)+8)) // 4 hi-order bytes of 12-byte value
#define UCHAR_12(p,i) ((uint8 *)PTR_12(p)+(i)) // byte of order i (LSB=0)
#define USHORT_12(p,i) ((uint16 *)((uint8 *)PTR_12(p)+(i))) // uint16 at byte of order i
#define ULONG_12(p,i) ((uint32 *)((uint8 *)PTR_12(p)+(i))) // uint32 at byte of order i
// Manipulation of a 64bit IEEE double
#define UINT164_D(p) ((uint16 *)(p) + 3)
#define UL_HI_D(p) ((uint32 *)(p) + 1)
#define UL_LO_D(p) ((uint32 *)(p))
#endif // defined(LITTLE_ENDIAN)
#if defined (BIG_ENDIAN)
#define U_EXP_12(p) ((uint16 *)PTR_12(p))
#define UL_MANHI_12(p) ((uint32 *)(PTR_12(p)+2))
#define UL_MANLO_12(p) ((uint32 *)(PTR_12(p)+6))
#define U_XT_12(p) ((uint16 *)(PTR_12(p)+10))
#define UL_LO_12(p) ((uint32 *)(PTR_12(p)+8))
#define UL_MED_12(p) ((uint32 *)(PTR_12(p)+4))
#define UL_HI_12(p) ((uint32 *)PTR_12(p))
#define UCHAR_12(p,i) ((uint8 *)PTR_12(p)+(11-(i)))
#define USHORT_12(p,i) ((uint16 *)((uint8 *)PTR_12(p)+10-(i)))
#define ULONG_12(p,i) ((uint32 *)((uint8 *)PTR_12(p)+8-(i)))
// Manipulation of a 64bit IEEE double
#define UINT164_D(p) ((uint16 *)(p))
#define UL_HI_D(p) ((uint32 *)(p))
#define UL_LO_D(p) ((uint32 *)(p) + 1)
#endif // defined(BIG_ENDIAN)
#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 )
//////////////////////////////////////////////////////////////////////////////
//
// Purpose: Convert a double into a _LDBL12
//
// Entry: double *px
//
// Exit: the corresponding _LDBL12 value is returned in *pld
//
static void dtold12(_LDBL12 *pld, const double *px)
{
uint32 msb = MSB_ULONG;
uint16 ldexp = 0;
uint16 exp = (*UINT164_D(px) & (uint16)0x7ff0) >> 4;
uint16 sign = *UINT164_D(px) & (uint16)0x8000;
uint32 manhi = *UL_HI_D(px) & 0xfffff;
uint32 manlo = *UL_LO_D(px);
switch (exp) {
case D_MAXEXP:
ldexp = LD_MAXEXP;
break;
case 0:
// check for zero
if (manhi == 0 && manlo == 0) {
*UL_MANHI_12(pld) = 0;
*UL_MANLO_12(pld) = 0;
*U_XT_12(pld) = 0;
*U_EXP_12(pld) = 0;
return;
}
// we have a denormal -- we'll normalize later
ldexp = (uint16) ((int16)exp - D_BIAS + LD_BIAS + 1);
msb = 0;
break;
default:
exp -= D_BIAS;
ldexp = (uint16) ((int16)exp + LD_BIAS);
break;
}
*UL_MANHI_12(pld) = msb | (manhi << 11) | (manlo >> 21);
*UL_MANLO_12(pld) = manlo << 11;
// normalize if necessary
while ((*UL_MANHI_12(pld) & MSB_ULONG) == 0) {
// shift left
*UL_MANHI_12(pld) = (*UL_MANHI_12(pld) << 1) |
(MSB_ULONG & *UL_MANLO_12(pld) ? 1: 0);
(*UL_MANLO_12(pld)) <<= 1;
ldexp --;
}
*U_EXP_12(pld) = sign | ldexp;
*U_XT_12(pld) = 0;
}
//////////////////////////////////////////////////////////////////////////////
//
// Purpose: add two uint32 numbers and return carry
//
// Entry: uint32 x, uint32 y : the numbers to be added
// uint32 *sum : where to store the result
//
// Exit: *sum receives the value of x+y
// the value of the carry is returned
//
static int addl(uint32 x, uint32 y, uint32 *sum)
{
uint32 r = x + y;
*sum = r;
return (r < x || r < y);
}
//////////////////////////////////////////////////////////////////////////////
//
// Purpose: add two _LDBL12 numbers. The numbers are added
// as 12-byte integers. Overflow is ignored.
//
// Entry: x,y: pointers to the operands
//
// Exit: *x receives the sum
//
static void add_12(_LDBL12 *x, _LDBL12 *y)
{
if (addl(*UL_LO_12(x),*UL_LO_12(y),UL_LO_12(x))) {
if (addl(*UL_MED_12(x),(uint32)1,UL_MED_12(x))) {
(*UL_HI_12(x))++;
}
}
if (addl(*UL_MED_12(x),*UL_MED_12(y),UL_MED_12(x))) {
(*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));
}
//////////////////////////////////////////////////////////////////////////////
//
// Purpose: Shift a _LDBL12 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)
//
static void shl_12(_LDBL12 *p)
{
uint32 c0 = (*UL_LO_12(p) & MSB_ULONG) ? 1: 0;
uint32 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;
}
static void shr_12(_LDBL12 *p)
{
uint32 c2 = (*UL_HI_12(p) & 0x1) ? MSB_ULONG: 0;
uint32 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;
}
//////////////////////////////////////////////////////////////////////////////
//
// Purpose: multiply two _LDBL12 numbers
//
// Entry: px,py: pointers to the _LDBL12 operands
//
// Exit: *px contains the product
//
static void ld12mul(_LDBL12 *px, _LDBL12 *py)
{
_LDBL12 tempman; // this is actually a 12-byte mantissa, not a 12-byte long double
*UL_LO_12(&tempman) = 0;
*UL_MED_12(&tempman) = 0;
*UL_HI_12(&tempman) = 0;
uint16 expx = *U_EXP_12(px);
uint16 expy = *U_EXP_12(py);
uint16 sign = (expx ^ expy) & (uint16)0x8000;
expx &= 0x7fff;
expy &= 0x7fff;
uint16 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;
}
}
int roffs = 0;
for (int i = 0; i < 5; i++) {
int poffs = i << 1;
int qoffs = 8;
for (int j = 5 - i; j > 0; j--) {
uint32 prod;
int carry;
uint16 *p, *q;
uint32 *r;
p = USHORT_12(px,poffs);
q = USHORT_12(py,qoffs);
r = ULONG_12(&tempman,roffs);
prod = (uint32)*p * (uint32)*q;
carry = addl(*r,prod,r);
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 ((int16)expsum > 0 &&
((*UL_HI_12(&tempman) & MSB_ULONG) == 0)) {
shl_12(&tempman);
expsum--;
}
if ((int16)expsum <= 0) {
bool sticky = false;
expsum--;
while ((int16)expsum < 0) {
if (*U_XT_12(&tempman) & 0x1) {
sticky = true;
}
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;
}
static void multtenpow12(_LDBL12 *pld12, int pow)
{
//////////////////////////////////////////////////////////////////////////////
//
// 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.
//
static _LDBL12 _pow10pos[] = {
#if defined(LITTLE_ENDIAN)
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0x02,0x40}}, // P0001
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x05,0x40}}, // P0002
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFA,0x08,0x40}}, // P0003
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9C,0x0C,0x40}}, // P0004
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xC3,0x0F,0x40}}, // P0005
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x24,0xF4,0x12,0x40}}, // P0006
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0x96,0x98,0x16,0x40}}, // P0007
{{0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x20,0xBC,0xBE,0x19,0x40}}, // P0008
{{0x00,0x00, 0x00,0x00,0x00,0x04,0xBF,0xC9,0x1B,0x8E,0x34,0x40}}, // P0016
{{0x00,0x00, 0x00,0xA1,0xED,0xCC,0xCE,0x1B,0xC2,0xD3,0x4E,0x40}}, // P0024
{{0x20,0xF0, 0x9E,0xB5,0x70,0x2B,0xA8,0xAD,0xC5,0x9D,0x69,0x40}}, // P0032
{{0xD0,0x5D, 0xFD,0x25,0xE5,0x1A,0x8E,0x4F,0x19,0xEB,0x83,0x40}}, // P0040
{{0x71,0x96, 0xD7,0x95,0x43,0x0E,0x05,0x8D,0x29,0xAF,0x9E,0x40}}, // P0048
{{0xF9,0xBF, 0xA0,0x44,0xED,0x81,0x12,0x8F,0x81,0x82,0xB9,0x40}}, // P0056
{{0xBF,0x3C, 0xD5,0xA6,0xCF,0xFF,0x49,0x1F,0x78,0xC2,0xD3,0x40}}, // P0064
{{0x6F,0xC6, 0xE0,0x8C,0xE9,0x80,0xC9,0x47,0xBA,0x93,0xA8,0x41}}, // P0128
{{0xBC,0x85, 0x6B,0x55,0x27,0x39,0x8D,0xF7,0x70,0xE0,0x7C,0x42}}, // P0192
{{0xBC,0xDD, 0x8E,0xDE,0xF9,0x9D,0xFB,0xEB,0x7E,0xAA,0x51,0x43}}, // P0256
{{0xA1,0xE6, 0x76,0xE3,0xCC,0xF2,0x29,0x2F,0x84,0x81,0x26,0x44}}, // P0320
{{0x28,0x10, 0x17,0xAA,0xF8,0xAE,0x10,0xE3,0xC5,0xC4,0xFA,0x44}}, // P0384
{{0xEB,0xA7, 0xD4,0xF3,0xF7,0xEB,0xE1,0x4A,0x7A,0x95,0xCF,0x45}}, // P0448
{{0x65,0xCC, 0xC7,0x91,0x0E,0xA6,0xAE,0xA0,0x19,0xE3,0xA3,0x46}}, // P0512
{{0x0D,0x65, 0x17,0x0C,0x75,0x81,0x86,0x75,0x76,0xC9,0x48,0x4D}}, // P1024
{{0x58,0x42, 0xE4,0xA7,0x93,0x39,0x3B,0x35,0xB8,0xB2,0xED,0x53}}, // P1536
{{0x4D,0xA7, 0xE5,0x5D,0x3D,0xC5,0x5D,0x3B,0x8B,0x9E,0x92,0x5A}}, // P2048
{{0xFF,0x5D, 0xA6,0xF0,0xA1,0x20,0xC0,0x54,0xA5,0x8C,0x37,0x61}}, // P2560
{{0xD1,0xFD, 0x8B,0x5A,0x8B,0xD8,0x25,0x5D,0x89,0xF9,0xDB,0x67}}, // P3072
{{0xAA,0x95, 0xF8,0xF3,0x27,0xBF,0xA2,0xC8,0x5D,0xDD,0x80,0x6E}}, // P3584
{{0x4C,0xC9, 0x9B,0x97,0x20,0x8A,0x02,0x52,0x60,0xC4,0x25,0x75}} // P4096
#endif
#if defined(BIG_ENDIAN)
{{0x40,0x02,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0001
{{0x40,0x05,0xC8,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0002
{{0x40,0x08,0xFA,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0003
{{0x40,0x0C,0x9C,0x40,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0004
{{0x40,0x0F,0xC3,0x50,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0005
{{0x40,0x12,0xF4,0x24,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0006
{{0x40,0x16,0x98,0x96,0x80,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0007
{{0x40,0x19,0xBE,0xBC,0x20,0x00,0x00,0x00,0x00,0x00, 0x00,0x00}}, // P0008
{{0x40,0x34,0x8E,0x1B,0xC9,0xBF,0x04,0x00,0x00,0x00, 0x00,0x00}}, // P0016
{{0x40,0x4E,0xD3,0xC2,0x1B,0xCE,0xCC,0xED,0xA1,0x00, 0x00,0x00}}, // P0024
{{0x40,0x69,0x9D,0xC5,0xAD,0xA8,0x2B,0x70,0xB5,0x9E, 0xF0,0x20}}, // P0032
{{0x40,0x83,0xEB,0x19,0x4F,0x8E,0x1A,0xE5,0x25,0xFD, 0x5D,0xD0}}, // P0040
{{0x40,0x9E,0xAF,0x29,0x8D,0x05,0x0E,0x43,0x95,0xD7, 0x96,0x71}}, // P0048
{{0x40,0xB9,0x82,0x81,0x8F,0x12,0x81,0xED,0x44,0xA0, 0xBF,0xF9}}, // P0056
{{0x40,0xD3,0xC2,0x78,0x1F,0x49,0xFF,0xCF,0xA6,0xD5, 0x3C,0xBF}}, // P0064
{{0x41,0xA8,0x93,0xBA,0x47,0xC9,0x80,0xE9,0x8C,0xE0, 0xC6,0x6F}}, // P0128
{{0x42,0x7C,0xE0,0x70,0xF7,0x8D,0x39,0x27,0x55,0x6B, 0x85,0xBC}}, // P0192
{{0x43,0x51,0xAA,0x7E,0xEB,0xFB,0x9D,0xF9,0xDE,0x8E, 0xDD,0xBC}}, // P0256
{{0x44,0x26,0x81,0x84,0x2F,0x29,0xF2,0xCC,0xE3,0x76, 0xE6,0xA1}}, // P0320
{{0x44,0xFA,0xC4,0xC5,0xE3,0x10,0xAE,0xF8,0xAA,0x17, 0x10,0x28}}, // P0384
{{0x45,0xCF,0x95,0x7A,0x4A,0xE1,0xEB,0xF7,0xF3,0xD4, 0xA7,0xEB}}, // P0448
{{0x46,0xA3,0xE3,0x19,0xA0,0xAE,0xA6,0x0E,0x91,0xC7, 0xCC,0x65}}, // P0512
{{0x4D,0x48,0xC9,0x76,0x75,0x86,0x81,0x75,0x0C,0x17, 0x65,0x0D}}, // P1024
{{0x53,0xED,0xB2,0xB8,0x35,0x3B,0x39,0x93,0xA7,0xE4, 0x42,0x58}}, // P1536
{{0x5A,0x92,0x9E,0x8B,0x3B,0x5D,0xC5,0x3D,0x5D,0xE5, 0xA7,0x4D}}, // P2048
{{0x61,0x37,0x8C,0xA5,0x54,0xC0,0x20,0xA1,0xF0,0xA6, 0x5D,0xFF}}, // P2560
{{0x67,0xDB,0xF9,0x89,0x5D,0x25,0xD8,0x8B,0x5A,0x8B, 0xFD,0xD1}}, // P3072
{{0x6E,0x80,0xDD,0x5D,0xC8,0xA2,0xBF,0x27,0xF3,0xF8, 0x95,0xAA}}, // P3584
{{0x75,0x25,0xC4,0x60,0x52,0x02,0x8A,0x20,0x97,0x9B, 0xC9,0x4C}} // P4096
#endif
};
static _LDBL12 _pow10neg[] = {
#if defined(LITTLE_ENDIAN)
{{0xCD,0xCC, 0xCD,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFB,0x3F}}, // N0001
{{0x71,0x3D, 0x0A,0xD7,0xA3,0x70,0x3D,0x0A,0xD7,0xA3,0xF8,0x3F}}, // N0002
{{0x5A,0x64, 0x3B,0xDF,0x4F,0x8D,0x97,0x6E,0x12,0x83,0xF5,0x3F}}, // N0003
{{0xC3,0xD3, 0x2C,0x65,0x19,0xE2,0x58,0x17,0xB7,0xD1,0xF1,0x3F}}, // N0004
{{0xD0,0x0F, 0x23,0x84,0x47,0x1B,0x47,0xAC,0xC5,0xA7,0xEE,0x3F}}, // N0005
{{0x40,0xA6, 0xB6,0x69,0x6C,0xAF,0x05,0xBD,0x37,0x86,0xEB,0x3F}}, // N0006
{{0x33,0x3D, 0xBC,0x42,0x7A,0xE5,0xD5,0x94,0xBF,0xD6,0xE7,0x3F}}, // N0007
{{0xC2,0xFD, 0xFD,0xCE,0x61,0x84,0x11,0x77,0xCC,0xAB,0xE4,0x3F}}, // N0008
{{0x2F,0x4C, 0x5B,0xE1,0x4D,0xC4,0xBE,0x94,0x95,0xE6,0xC9,0x3F}}, // N0016
{{0x92,0xC4, 0x53,0x3B,0x75,0x44,0xCD,0x14,0xBE,0x9A,0xAF,0x3F}}, // N0024
{{0xDE,0x67, 0xBA,0x94,0x39,0x45,0xAD,0x1E,0xB1,0xCF,0x94,0x3F}}, // N0032
{{0x24,0x23, 0xC6,0xE2,0xBC,0xBA,0x3B,0x31,0x61,0x8B,0x7A,0x3F}}, // N0040
{{0x61,0x55, 0x59,0xC1,0x7E,0xB1,0x53,0x7C,0x12,0xBB,0x5F,0x3F}}, // N0048
{{0xD7,0xEE, 0x2F,0x8D,0x06,0xBE,0x92,0x85,0x15,0xFB,0x44,0x3F}}, // N0056
{{0x24,0x3F, 0xA5,0xE9,0x39,0xA5,0x27,0xEA,0x7F,0xA8,0x2A,0x3F}}, // N0064
{{0x7D,0xAC, 0xA1,0xE4,0xBC,0x64,0x7C,0x46,0xD0,0xDD,0x55,0x3E}}, // N0128
{{0x63,0x7B, 0x06,0xCC,0x23,0x54,0x77,0x83,0xFF,0x91,0x81,0x3D}}, // N0192
{{0x91,0xFA, 0x3A,0x19,0x7A,0x63,0x25,0x43,0x31,0xC0,0xAC,0x3C}}, // N0256
{{0x21,0x89, 0xD1,0x38,0x82,0x47,0x97,0xB8,0x00,0xFD,0xD7,0x3B}}, // N0320
{{0xDC,0x88, 0x58,0x08,0x1B,0xB1,0xE8,0xE3,0x86,0xA6,0x03,0x3B}}, // N0384
{{0xC6,0x84, 0x45,0x42,0x07,0xB6,0x99,0x75,0x37,0xDB,0x2E,0x3A}}, // N0448
{{0x33,0x71, 0x1C,0xD2,0x23,0xDB,0x32,0xEE,0x49,0x90,0x5A,0x39}}, // N0512
{{0xA6,0x87, 0xBE,0xC0,0x57,0xDA,0xA5,0x82,0xA6,0xA2,0xB5,0x32}}, // N1024
{{0xE2,0x68, 0xB2,0x11,0xA7,0x52,0x9F,0x44,0x59,0xB7,0x10,0x2C}}, // N1536
{{0x25,0x49, 0xE4,0x2D,0x36,0x34,0x4F,0x53,0xAE,0xCE,0x6B,0x25}}, // N2048
{{0x8F,0x59, 0x04,0xA4,0xC0,0xDE,0xC2,0x7D,0xFB,0xE8,0xC6,0x1E}}, // N2560
{{0x9E,0xE7, 0x88,0x5A,0x57,0x91,0x3C,0xBF,0x50,0x83,0x22,0x18}}, // N3072
{{0x4E,0x4B, 0x65,0x62,0xFD,0x83,0x8F,0xAF,0x06,0x94,0x7D,0x11}}, // N3584
{{0xE4,0x2D, 0xDE,0x9F,0xCE,0xD2,0xC8,0x04,0xDD,0xA6,0xD8,0x0A}} // N4096
#endif
#if defined(BIG_ENDIAN)
{{0x3F,0xFB,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCD, 0xCC,0xCD}}, // N0001
{{0x3F,0xF8,0xA3,0xD7,0x0A,0x3D,0x70,0xA3,0xD7,0x0A, 0x3D,0x71}}, // N0002
{{0x3F,0xF5,0x83,0x12,0x6E,0x97,0x8D,0x4F,0xDF,0x3B, 0x64,0x5A}}, // N0003
{{0x3F,0xF1,0xD1,0xB7,0x17,0x58,0xE2,0x19,0x65,0x2C, 0xD3,0xC3}}, // N0004
{{0x3F,0xEE,0xA7,0xC5,0xAC,0x47,0x1B,0x47,0x84,0x23, 0x0F,0xD0}}, // N0005
{{0x3F,0xEB,0x86,0x37,0xBD,0x05,0xAF,0x6C,0x69,0xB6, 0xA6,0x40}}, // N0006
{{0x3F,0xE7,0xD6,0xBF,0x94,0xD5,0xE5,0x7A,0x42,0xBC, 0x3D,0x33}}, // N0007
{{0x3F,0xE4,0xAB,0xCC,0x77,0x11,0x84,0x61,0xCE,0xFD, 0xFD,0xC2}}, // N0008
{{0x3F,0xC9,0xE6,0x95,0x94,0xBE,0xC4,0x4D,0xE1,0x5B, 0x4C,0x2F}}, // N0016
{{0x3F,0xAF,0x9A,0xBE,0x14,0xCD,0x44,0x75,0x3B,0x53, 0xC4,0x92}}, // N0024
{{0x3F,0x94,0xCF,0xB1,0x1E,0xAD,0x45,0x39,0x94,0xBA, 0x67,0xDE}}, // N0032
{{0x3F,0x7A,0x8B,0x61,0x31,0x3B,0xBA,0xBC,0xE2,0xC6, 0x23,0x24}}, // N0040
{{0x3F,0x5F,0xBB,0x12,0x7C,0x53,0xB1,0x7E,0xC1,0x59, 0x55,0x61}}, // N0048
{{0x3F,0x44,0xFB,0x15,0x85,0x92,0xBE,0x06,0x8D,0x2F, 0xEE,0xD7}}, // N0056
{{0x3F,0x2A,0xA8,0x7F,0xEA,0x27,0xA5,0x39,0xE9,0xA5, 0x3F,0x24}}, // N0064
{{0x3E,0x55,0xDD,0xD0,0x46,0x7C,0x64,0xBC,0xE4,0xA1, 0xAC,0x7D}}, // N0128
{{0x3D,0x81,0x91,0xFF,0x83,0x77,0x54,0x23,0xCC,0x06, 0x7B,0x63}}, // N0192
{{0x3C,0xAC,0xC0,0x31,0x43,0x25,0x63,0x7A,0x19,0x3A, 0xFA,0x91}}, // N0256
{{0x3B,0xD7,0xFD,0x00,0xB8,0x97,0x47,0x82,0x38,0xD1, 0x89,0x21}}, // N0320
{{0x3B,0x03,0xA6,0x86,0xE3,0xE8,0xB1,0x1B,0x08,0x58, 0x88,0xDC}}, // N0384
{{0x3A,0x2E,0xDB,0x37,0x75,0x99,0xB6,0x07,0x42,0x45, 0x84,0xC6}}, // N0448
{{0x39,0x5A,0x90,0x49,0xEE,0x32,0xDB,0x23,0xD2,0x1C, 0x71,0x33}}, // N0512
{{0x32,0xB5,0xA2,0xA6,0x82,0xA5,0xDA,0x57,0xC0,0xBE, 0x87,0xA6}}, // N1024
{{0x2C,0x10,0xB7,0x59,0x44,0x9F,0x52,0xA7,0x11,0xB2, 0x68,0xE2}}, // N1536
{{0x25,0x6B,0xCE,0xAE,0x53,0x4F,0x34,0x36,0x2D,0xE4, 0x49,0x25}}, // N2048
{{0x1E,0xC6,0xE8,0xFB,0x7D,0xC2,0xDE,0xC0,0xA4,0x04, 0x59,0x8F}}, // N2560
{{0x18,0x22,0x83,0x50,0xBF,0x3C,0x91,0x57,0x5A,0x88, 0xE7,0x9E}}, // N3072
{{0x11,0x7D,0x94,0x06,0xAF,0x8F,0x83,0xFD,0x62,0x65, 0x4B,0x4E}}, // N3584
{{0x0A,0xD8,0xA6,0xDD,0x04,0xC8,0xD2,0xCE,0x9F,0xDE, 0x2D,0xE4}} // N4096
#endif
};
_LDBL12 *pow_10p = _pow10pos - 8;
if (pow == 0) {
return;
}
if (pow < 0) {
pow = -pow;
pow_10p = _pow10neg - 8;
}
while (pow) {
pow_10p += 7;
int last3 = pow & 0x7; // the 3 LSBits of pow
pow >>= 3;
if (last3 == 0) {
continue;
}
_LDBL12 *py = pow_10p + last3;
// do an exact 12 byte multiplication
if (*U_XT_12(py) >= 0x8000) {
_LDBL12 unround = *py; // copy number
(*UL_MANLO_12(&unround))--; // unround adjacent byte
py = &unround; // point to new operand
}
ld12mul(pld12, py);
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Purpose:
// _ecvt converts value to a null terminated string of
// UNICODE digits, and returns a pointer to the result.
// The position of the decimal point relative to the
// beginning of the string is stored indirectly through
// decpt, where negative means to the left of the returned
// digits. If the sign of the result is negative, the
// bool pointed to by negative is set to true, otherwise it is
// false. The low order digit is rounded.
//
// Entry:
// double value - number to be converted
// int digits - number of digits after decimal point
//
// Exit:
// returns pointer to the character representation of value.
// int *decpt - pointer to int with position of decimal point
// bool *negative - pointer to bool for if value < 0.
//
bool Class_System_Number::g_ecvt(double value,
int digits,
ClassVector_bartok_char * buf,
int *decpt,
bool *negative)
{
if ((uint32)digits > buf->length - 1) {
digits = buf->length - 1;
}
bartok_char *man = buf->values;
// useful constants (see algorithm explanation below)
const uint16 log2hi = 0x4d10;
const uint16 log2lo = 0x4d;
const uint16 log4hi = 0x9a;
const uint32 c = 0x134312f4;
#if defined(LITTLE_ENDIAN)
_LDBL12 ld12_one_tenth = {
{0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xfb,0x3f}
};
#endif
#if defined(BIG_ENDIAN)
_LDBL12 ld12_one_tenth = {
{0x3f,0xfb,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc}
};
#endif
// convert the double into a 12-byte long double.
_LDBL12 ld12;
dtold12(&ld12, &value);
uint16 expn = *U_EXP_12(&ld12);
uint32 manhi = *UL_MANHI_12(&ld12);
uint32 manlo = *UL_MANLO_12(&ld12);
uint16 sign = expn & MSB_USHORT;
expn &= 0x7fff;
*U_EXP_12(&ld12) = expn;
*negative = (sign != 0);
if (expn == 0 && manhi == 0 && manlo == 0) {
zero_fos:
*decpt = 0;
*negative = false;
man[0] = '0';
man[1] = '\0';
return true;
}
if (expn == 0x7fff) {
man[0] = '\0';
*decpt = SCALE_NAN;
if (_IS_MAN_INF(sign, manhi, manlo)) {
*decpt = SCALE_INF; // infinity
}
return false;
}
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 tentatively 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 uint32 is use to accommodate r, and
// there is an implied decimal point in the middle.
uint16 hh = expn >> 8;
uint16 ll = expn & (uint16)0xff;
uint16 mm = (uint16) (manhi >> 24); // the two most significant bytes of the mantissa.
int32 r = (int32)log2hi*(int32)expn + log2lo*hh + log4hi*mm - c;
// the corresponding power of 10
int32 ir = (int16)(r >> 16); // ir = floor(r)
// 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.
// multiply by 10^(-ir)
multtenpow12(&ld12,-ir);
// if ld12 >= 1.0 then divide by 10.0
if (*U_EXP_12(&ld12) >= 0x3fff) {
ir++;
ld12mul(&ld12,&ld12_one_tenth);
}
*decpt = ir;
int 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 (int 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);
}
}
bartok_char *p = man;
for (int digcount = digits + 1; digcount > 0; digcount--) {
_LDBL12 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 most significant byte of exponent
*p++ = (char) (*UCHAR_12(&ld12,11) + '0');
*UCHAR_12(&ld12,11) = 0;
}
bartok_char 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 >= man && *p == '9'; p--) {
*p = '0';
}
if (p < man) {
p++;
(*decpt)++;
}
(*p)++;
}
else {
2008-11-17 18:29:00 -05:00
// We probably don't want to truncate all of the zeros!
2008-03-05 09:52:00 -05:00
for (; p >= man && *p == '0'; p--) {
// remove extra zeros;
}
if (p < man) {
goto zero_fos;
}
}
man[(p - man + 1)] = '\0';
return true;
}
}
double Class_System_Number::g_atof(struct ClassVector_uint8 *a)
{
Assert(!"atof");
return 0;
}
//
///////////////////////////////////////////////////////////////// End of File.