fixed: Big::FromDouble(double) sometimes sets a wrong value

there was SetSign() used when the value was not
       defined, and also was a small mistake when the mantissa 
       was equal one word (on 32bit platforms)
added: uint Big::ToDouble(double&) - converting into double


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@49 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2007-07-29 22:42:45 +00:00
parent 692ff5406e
commit 25f876762a
1 changed files with 173 additions and 26 deletions

View File

@ -1725,18 +1725,14 @@ public:
union
{
double d;
unsigned int u[2]; // two 32bit words
uint u[2]; // two 32bit words
} temp;
temp.d = value;
info = 0;
if( temp.u[1] & 0x80000000u )
SetSign();
int e = (temp.u[1] & 0x7FF00000u) >> 20;
unsigned int m1 = ((temp.u[1] & 0xFFFFFu) << 11) | (temp.u[0] >> 21);
unsigned int m2 = temp.u[0] << 11;
sint e = ( temp.u[1] & 0x7FF00000u) >> 20;
uint m1 = ((temp.u[1] & 0xFFFFFu) << 11) | (temp.u[0] >> 21);
uint m2 = temp.u[0] << 11;
if( e == 2047 )
{
@ -1756,7 +1752,9 @@ public:
// where "1.F" is intended to represent the binary number
// created by prefixing F with an implicit leading 1 and a binary point.
FromDouble_SetExpAndMan(e - 1023 - man*TTMATH_BITS_PER_UINT + 1, 0x80000000u, m1, m2);
FromDouble_SetExpAndMan(bool(temp.u[1] & 0x80000000u),
e - 1023 - man*TTMATH_BITS_PER_UINT + 1, 0x80000000u,
m1, m2);
// we do not have to call Standardizing() here
// because the mantissa will have the highest bit set
@ -1771,8 +1769,14 @@ public:
// then V=(-1)**S * 2 ** (-1022) * (0.F)
// These are "unnormalized" values.
FromDouble_SetExpAndMan(e - 1022 - man*TTMATH_BITS_PER_UINT + 1, 0, m1, m2);
Standardizing();
UInt<2> m;
m.table[1] = m1;
m.table[0] = m2;
uint moved = m.CompensationToLeft();
FromDouble_SetExpAndMan(bool(temp.u[1] & 0x80000000u),
e - 1022 - man*TTMATH_BITS_PER_UINT + 1 - moved, 0,
m.table[1], m.table[2]);
}
else
{
@ -1788,23 +1792,29 @@ public:
private:
void FromDouble_SetExpAndMan(int e, unsigned int mhighest,
unsigned int m1, unsigned int m2)
void FromDouble_SetExpAndMan(bool is_sign, int e, uint mhighest, uint m1, uint m2)
{
exponent = e;
if( man > 1 )
{
mantissa.table[man-1] = m1 | mhighest;
mantissa.table[man-2] = m2;
mantissa.table[sint(man-2)] = m2;
// although man>1 we're using casting into sint
// to get rid from a warning which generates Microsoft Visual:
// warning C4307: '*' : integral constant overflow
for(unsigned int i=0 ; i<man-2 ; ++i)
for(uint i=0 ; i<man-2 ; ++i)
mantissa.table[i] = 0;
}
else
{
mantissa.table[0] = m1 | mhighest;
}
info = 0;
if( is_sign )
SetSign();
}
@ -1829,13 +1839,9 @@ public:
} temp;
temp.d = value;
info = 0;
if( temp.u & 0x8000000000000000ul )
SetSign();
int e = (temp.u & 0x7FF0000000000000ul) >> 52;
uint m = (temp.u & 0xFFFFFFFFFFFFFul) << 11;
sint e = (temp.u & 0x7FF0000000000000ul) >> 52;
uint m = (temp.u & 0xFFFFFFFFFFFFFul) << 11;
if( e == 2047 )
{
@ -1855,7 +1861,9 @@ public:
// where "1.F" is intended to represent the binary number
// created by prefixing F with an implicit leading 1 and a binary point.
FromDouble_SetExpAndMan(e - 1023 - man*TTMATH_BITS_PER_UINT + 1, 0x8000000000000000ul, m);
FromDouble_SetExpAndMan(bool(temp.u & 0x8000000000000000ul),
e - 1023 - man*TTMATH_BITS_PER_UINT + 1,
0x8000000000000000ul, m);
// we do not have to call Standardizing() here
// because the mantissa will have the highest bit set
@ -1870,7 +1878,8 @@ public:
// then V=(-1)**S * 2 ** (-1022) * (0.F)
// These are "unnormalized" values.
FromDouble_SetExpAndMan(e - 1022 - man*TTMATH_BITS_PER_UINT + 1, 0, m);
FromDouble_SetExpAndMan(bool(temp.u & 0x8000000000000000ul),
e - 1022 - man*TTMATH_BITS_PER_UINT + 1, 0, m);
Standardizing();
}
else
@ -1886,13 +1895,17 @@ public:
private:
void FromDouble_SetExpAndMan(int e, uint mhighest, uint m)
void FromDouble_SetExpAndMan(bool is_sign, sint e, uint mhighest, uint m)
{
exponent = e;
mantissa.table[man-1] = m | mhighest;
for(unsigned int i=0 ; i<man-1 ; ++i)
for(uint i=0 ; i<man-1 ; ++i)
mantissa.table[i] = 0;
info = 0;
if( is_sign )
SetSign();
}
#endif
@ -1900,6 +1913,140 @@ private:
public:
/*!
this method converts from this class into the 'double'
if the value is too big:
'result' will be +/-infinity (depending on the sign)
and the method returns 1
if the value is too small:
'result' will be 0
and the method returns 1
*/
uint ToDouble(double & result) const
{
// sizeof(double) should be 8 (64 bits), this is actually not a runtime
// error but I leave it at the moment as is
TTMATH_ASSERT( sizeof(double) == 8 )
if( IsZero() )
{
result = 0.0;
return 0;
}
sint e_correction = sint(man*TTMATH_BITS_PER_UINT) - 1;
if( exponent >= 1024 - e_correction )
{
// +/- infinity
result = ToDouble_SetDouble( IsSign(), 2047, 0, true);
return 1;
}
else
if( exponent <= -1023 - 52 - e_correction )
{
// too small value - we assume that there'll be a zero
result = 0;
// and return a carry
return 1;
}
sint e = exponent.ToInt() + e_correction;
if( e <= -1023 )
{
// -1023-52 < e <= -1023 (unnormalized value)
result = ToDouble_SetDouble( IsSign(), 0, -(e + 1023));
}
else
{
// -1023 < e < 1024
result = ToDouble_SetDouble( IsSign(), e + 1023, -1);
}
return 0;
}
private:
#ifdef TTMATH_PLATFORM32
// 32bit platforms
double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false) const
{
union
{
double d;
uint u[2]; // two 32bit words
} temp;
temp.u[0] = temp.u[1] = 0;
if( is_sign )
temp.u[1] |= 0x80000000u;
temp.u[1] |= (e << 20) & 0x7FF00000u;
if( infinity )
return temp.d;
UInt<2> m;
m.table[1] = mantissa.table[man-1];
m.table[0] = ( man > 1 ) ? mantissa.table[sint(man-2)] : 0;
// although man>1 we're using casting into sint
// to get rid from a warning which generates Microsoft Visual:
// warning C4307: '*' : integral constant overflow
m.Rcr( 12 + move );
m.table[1] &= 0xFFFFFu; // cutting the 20 bit (when 'move' was -1)
temp.u[1] |= m.table[1];
temp.u[0] |= m.table[0];
return temp.d;
}
#else
// 64bit platforms
double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false) const
{
union
{
double d;
uint u; // 64bit word
} temp;
temp.u = 0;
if( is_sign )
temp.u |= 0x8000000000000000ul;
temp.u |= (e << 52) & 0x7FF0000000000000ul;
if( infinity )
return temp.d;
uint m = mantissa.table[man-1];
m >>= ( 12 + move );
m &= 0xFFFFFFFFFFFFFul; // cutting the 20 bit (when 'move' was -1)
temp.u |= m;
return temp.d;
}
#endif
public:
/*!
an operator= for converting 'sint' to this class
*/