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:
parent
692ff5406e
commit
25f876762a
|
@ -1725,18 +1725,14 @@ public:
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
double d;
|
double d;
|
||||||
unsigned int u[2]; // two 32bit words
|
uint u[2]; // two 32bit words
|
||||||
} temp;
|
} temp;
|
||||||
|
|
||||||
temp.d = value;
|
temp.d = value;
|
||||||
|
|
||||||
info = 0;
|
sint e = ( temp.u[1] & 0x7FF00000u) >> 20;
|
||||||
if( temp.u[1] & 0x80000000u )
|
uint m1 = ((temp.u[1] & 0xFFFFFu) << 11) | (temp.u[0] >> 21);
|
||||||
SetSign();
|
uint m2 = temp.u[0] << 11;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if( e == 2047 )
|
if( e == 2047 )
|
||||||
{
|
{
|
||||||
|
@ -1756,7 +1752,9 @@ public:
|
||||||
// where "1.F" is intended to represent the binary number
|
// where "1.F" is intended to represent the binary number
|
||||||
// created by prefixing F with an implicit leading 1 and a binary point.
|
// 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
|
// we do not have to call Standardizing() here
|
||||||
// because the mantissa will have the highest bit set
|
// because the mantissa will have the highest bit set
|
||||||
|
@ -1771,8 +1769,14 @@ public:
|
||||||
// then V=(-1)**S * 2 ** (-1022) * (0.F)
|
// then V=(-1)**S * 2 ** (-1022) * (0.F)
|
||||||
// These are "unnormalized" values.
|
// These are "unnormalized" values.
|
||||||
|
|
||||||
FromDouble_SetExpAndMan(e - 1022 - man*TTMATH_BITS_PER_UINT + 1, 0, m1, m2);
|
UInt<2> m;
|
||||||
Standardizing();
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1788,23 +1792,29 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void FromDouble_SetExpAndMan(int e, unsigned int mhighest,
|
void FromDouble_SetExpAndMan(bool is_sign, int e, uint mhighest, uint m1, uint m2)
|
||||||
unsigned int m1, unsigned int m2)
|
|
||||||
{
|
{
|
||||||
exponent = e;
|
exponent = e;
|
||||||
|
|
||||||
if( man > 1 )
|
if( man > 1 )
|
||||||
{
|
{
|
||||||
mantissa.table[man-1] = m1 | mhighest;
|
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;
|
mantissa.table[i] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mantissa.table[0] = m1 | mhighest;
|
mantissa.table[0] = m1 | mhighest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info = 0;
|
||||||
|
if( is_sign )
|
||||||
|
SetSign();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1829,13 +1839,9 @@ public:
|
||||||
} temp;
|
} temp;
|
||||||
|
|
||||||
temp.d = value;
|
temp.d = value;
|
||||||
|
|
||||||
info = 0;
|
sint e = (temp.u & 0x7FF0000000000000ul) >> 52;
|
||||||
if( temp.u & 0x8000000000000000ul )
|
uint m = (temp.u & 0xFFFFFFFFFFFFFul) << 11;
|
||||||
SetSign();
|
|
||||||
|
|
||||||
int e = (temp.u & 0x7FF0000000000000ul) >> 52;
|
|
||||||
uint m = (temp.u & 0xFFFFFFFFFFFFFul) << 11;
|
|
||||||
|
|
||||||
if( e == 2047 )
|
if( e == 2047 )
|
||||||
{
|
{
|
||||||
|
@ -1855,7 +1861,9 @@ public:
|
||||||
// where "1.F" is intended to represent the binary number
|
// where "1.F" is intended to represent the binary number
|
||||||
// created by prefixing F with an implicit leading 1 and a binary point.
|
// 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
|
// we do not have to call Standardizing() here
|
||||||
// because the mantissa will have the highest bit set
|
// because the mantissa will have the highest bit set
|
||||||
|
@ -1870,7 +1878,8 @@ public:
|
||||||
// then V=(-1)**S * 2 ** (-1022) * (0.F)
|
// then V=(-1)**S * 2 ** (-1022) * (0.F)
|
||||||
// These are "unnormalized" values.
|
// 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();
|
Standardizing();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1886,13 +1895,17 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void FromDouble_SetExpAndMan(int e, uint mhighest, uint m)
|
void FromDouble_SetExpAndMan(bool is_sign, sint e, uint mhighest, uint m)
|
||||||
{
|
{
|
||||||
exponent = e;
|
exponent = e;
|
||||||
mantissa.table[man-1] = m | mhighest;
|
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;
|
mantissa.table[i] = 0;
|
||||||
|
|
||||||
|
info = 0;
|
||||||
|
if( is_sign )
|
||||||
|
SetSign();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1900,6 +1913,140 @@ private:
|
||||||
|
|
||||||
public:
|
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
|
an operator= for converting 'sint' to this class
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue