Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Reading an 80-bit long double into a 64-bit dotnet double...

47 views
Skip to first unread message

Nathan Baulch

unread,
Aug 14, 2003, 9:35:07 PM8/14/03
to
I have a 10 byte long double in a file on disk.
Unfortunately it looks like dotnet doesn't support long doubles.

Can anybody suggest how I would read those 80-bits into a standard 64-bit
dotnet double?
I am happy to assume that my long double will fall within the standard
double range.


Nathan


Jon Skeet

unread,
Aug 15, 2003, 3:13:04 AM8/15/03
to

I wrote some code to do this a while ago in response to another
newsgroup post. It wasn't extensively tested, but you may find it
useful anyway.

Here's the code - hope it's okay for you.

/// <summary>Converts the given extended-format byte array (which
/// is assumed to be in little-endian form) to a .NET Double,
/// as closely as possible. Values which are too small to be
/// represented are returned as an appropriately signed 0. Values
/// which are too large
/// to be represented (but not infinite) are returned as
/// Double.NaN,
/// as are unsupported values and actual NaN values.</summary>
public static double ExtendedToDouble (byte[] extended)
{
// Read information from the extended form - variable names as
// used in http://cch.loria.fr/documentation/
// IEEE754/numerical_comp_guide/ncg_math.doc.html
int s = extended[9] >> 7;

int e = (((extended[9] & 0x7f) << 8) | (extended[8]));

int j = extended[7] >> 7;
long f=extended[7] & 0x7f;
for (int i=6; i >= 0; i--)
{
f = (f << 8) | extended[i];
}

// Now go through each possibility
if (j==1)
{
if (e==0)
{
// Value = (-1)^s * 2^16382*1.f
// (Pseudo-denormal numbers)
// Anything pseudo-denormal in extended form is
// definitely 0 in double form.
return FromComponents (s, 0, 0);
}
else if (e != 32767)
{
// Value = (-1)^s * 2^(e-16383)*1.f (Normal numbers)

// Lose the last 11 bits of the fractional part
f = f>>11;

// Convert exponent to the appropriate one
e += 1023-16383;

// Out of range - too large
if (e > 2047)
return Double.NaN;

// Out of range - too small
if (e < 0)
{
// See if we can get a subnormal version
if (e >= -51)
{
// Put a 1 at the front of f
f = f | (1<<52);
// Now shift it appropriately
f = f >> (1-e);
// Return a subnormal version
return FromComponents (s, 0, f);
}
else // Return an appropriate 0
{
return FromComponents (s, 0, 0);
}
}

return FromComponents (s, e, f);
}
else
{
if (f==0)
{
// Value = positive/negative infinity
return FromComponents (s, 2047, 0);
}
else
{
// Don't really understand the document about the
// remaining two values, but they're both NaN...
return Double.NaN;
}
}
}
else // Okay, j==0
{
if (e==0)
{
// Either 0 or a subnormal number, which will
// still be 0 in double form
return FromComponents (s, 0, 0);
}
else
{
// Unsupported
return Double.NaN;
}
}
}

/// <summary>Returns a double from the IEEE sign/exponent/fraction
/// components.</summary>
private static double FromComponents (int s, int e, long f)
{
byte[] data = new byte[8];

// Put the data into appropriate slots based on endianness.
if (BitConverter.IsLittleEndian)
{
data[7] = (byte) ((s<<7) | (e>>4));
data[6] = (byte) (((e&0xf) << 4) | (int)(f >> 48));
data[5] = (byte) ((f & 0xff0000000000L) >> 40);
data[4] = (byte) ((f & 0xff00000000L) >> 32);
data[3] = (byte) ((f & 0xff000000L) >> 24);
data[2] = (byte) ((f & 0xff0000L) >> 16);
data[1] = (byte) ((f & 0xff00L) >> 8);
data[0] = (byte) (f & 0xff);
}
else
{
data[0] = (byte) ((s<<7) | (e>>4));
data[1] = (byte) (((e&0xf) << 4) | (int)(f >> 48));
data[2] = (byte) ((f & 0xff0000000000L) >> 40);
data[3] = (byte) ((f & 0xff00000000L) >> 32);
data[4] = (byte) ((f & 0xff000000L) >> 24);
data[5] = (byte) ((f & 0xff0000L) >> 16);
data[6] = (byte) ((f & 0xff00L) >> 8);
data[7] = (byte) (f & 0xff);
}

return BitConverter.ToDouble (data, 0);
}

--
Jon Skeet - <sk...@pobox.com>
http://www.pobox.com/~skeet/
If replying to the group, please do not mail me too

0 new messages