Click here to Skip to main content
15,896,557 members
Articles / Programming Languages / C#

Interpreting Intel 80-bit Long Double Byte Arrays

Rate me:
Please Sign up or sign in to vote.
3.57/5 (20 votes)
5 Apr 20044 min read 53.5K   538   11  
A simple BitConverter class that is capable of reading and writing Intel 80-bit long doubles.
using System;
using System.Security.Cryptography;

namespace Nato.LongDouble
{
	public class SelfTest
	{
		static void Main() 
		{
			Test1();
			Test2();
			Test3();
			Test4();
		}

		private static void Test1()
		{
			Console.WriteLine("Test 1: Important boundary numbers.");

			byte[][] knownByteSequences = new byte[][] {
														   new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F},		// quiet nan with max f
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x7F},		// quiet nan with min f
														   new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0x7F},		// signaling nan with max f
														   new byte[] {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x7F},		// signaling nan with min f

														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},		// 0
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x3F},		// 1
														   new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F},		// long double max normal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00},		// long double min positive normal
														   new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00,0x00},		// long double max subnormal
														   new byte[] {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},		// long double min positive subnormal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x7F},		// infinity
														   new byte[] {0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x43},		// double max normal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x3C},		// double min positive normal
														   new byte[] {0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x3C},		// double max subnormal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xCD,0x3B},		// double min positive subnormal

														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},		// -0
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0xBF},		// -1
														   new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF},		// long double min normal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x80},		// long double max negative normal
														   new byte[] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x00,0x80},		// long double min subnormal
														   new byte[] {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},		// long double max negative subnormal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0xFF},		// -infinity
														   new byte[] {0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xC3},		// double min normal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0xBC},		// double max negative normal
														   new byte[] {0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xBC},		// double min subnormal
														   new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xCD,0xBB}};		// double max negative subnormal

			string[] expectedResults = new string[] {
														"NaN",
														"NaN",
														"NaN",
														"NaN",

														"0",
														"1",
														"Overflow",
														"0",
														"0",
														"0",
														"Infinity",
														"1.7976931348623157E+308",
														"2.2250738585072014E-308",
														"2.2250738585072004E-308",
														"4.9406564584124654E-324",

														"0",
														"-1",
														"Overflow",
														"0",
														"0",
														"0",
														"-Infinity",
														"-1.7976931348623157E+308",
														"-2.2250738585072014E-308",
														"-2.2250738585072004E-308",
														"-4.9406564584124654E-324"};

			for(sbyte i = 0; i < knownByteSequences.Length; i++)
			{
				string s1 = expectedResults[i];
				string s2;
				try
				{
					s2 = Nato.LongDouble.BitConverter.ToDouble(knownByteSequences[i],0).ToString("G17");
				}
				catch(OverflowException)
				{
					s2 = "Overflow";
				}
				catch(NotSupportedException)
				{
					s2 = "NotSupported";
				}
				Console.WriteLine("\t" + (s1 == s2 ? "same" : "diff") + " (" + s1 + " -> " + s2 + ")");
			}
		}

		private static void Test2()
		{
			Console.WriteLine("Test 2: Random doubles, double comparison.");

			byte[] bytes = new byte[107];
			new RNGCryptoServiceProvider().GetBytes(bytes);

			for(int i = 0; i < 100; i++)
			{
				double d1 = System.BitConverter.ToDouble(bytes,i);
				byte[] b = Nato.LongDouble.BitConverter.GetBytes(d1);
				double d2 = Nato.LongDouble.BitConverter.ToDouble(b,0);

				string s1 = d1.ToString("G17");
				string s2 = d2.ToString("G17");
				Console.WriteLine("\t" + (s1 == s2 ? "same" : "diff") + " (" + s1 + " -> " + s2 + ")");
			}
		}

		private static void Test3()
		{
			Console.WriteLine("Test 3: Random normal doubles, byte comparison.");

			byte[] bytes = new byte[1609];
			new RNGCryptoServiceProvider().GetBytes(bytes);

			for(int i = 0; i < 1600; i++)
			{
				byte[] b1 = new byte[10];
				Array.Copy(bytes,i,b1,0,10);
				b1[7] |= 0x80;
				try
				{
					double d = Nato.LongDouble.BitConverter.ToDouble(b1,0);
					if(Math.Abs(d) > 2.2250738585072004E-308 && !double.IsNaN(d))
					{
						byte[] b2 = Nato.LongDouble.BitConverter.GetBytes(d);

						string s1 = string.Empty;
						string s2 = string.Empty;
						for(int j = 9; j >= 2; j--)
						{
							if(j < 9 && (j % 2) == 1)
							{
								s1 += " ";
								s2 += " ";
							}
							if(b1[j] < 0x10)
								s1 += "0";
							if(b2[j] < 0x10)
								s2 += "0";
							s1 += b1[j].ToString("X");
							s2 += b2[j].ToString("X");
						}
						Console.WriteLine("\t" + (s1 == s2 ? "same" : "diff") + " (" + s1 + " .... -> " + s2 + " ....)");
					}
				}
				catch(OverflowException) {}
				catch(NotSupportedException) {}
			}
		}

		private static void Test4()
		{
			Console.WriteLine("Test 4: Random subnormal doubles, byte comparison.");

			byte[] bytes = new byte[509];
			new RNGCryptoServiceProvider().GetBytes(bytes);

			for(int i = 0; i < 500; i++)
			{
				byte[] b1 = new byte[10];
				Array.Copy(bytes,i,b1,0,10);
				b1[9] |= 0x3B;
				b1[8] |= 0xC0;
				b1[7] |= 0x80;	//make sure j is not zero
				try
				{
					double d = Nato.LongDouble.BitConverter.ToDouble(b1,0);
					if(d != 0 && Math.Abs(d) < 2.2250738585072014E-308 && !double.IsNaN(d))
					{
						byte[] b2 = Nato.LongDouble.BitConverter.GetBytes(d);

						int e = 1 - (((((b1[9] & 0x7F) << 8) | b1[8]) - 0x3C00) >> 2);
						if(e > 8)
							e = 8;

						string s1 = string.Empty;
						string s2 = string.Empty;
						for(int j = 9; j >= 0; j--)
						{
							if(j < 9 && (j % 2) == 1)
							{
								s1 += " ";
								s2 += " ";
							}
							if(j < e)
							{
								s1 += "..";
								s2 += "..";
							}
							else
							{
								if(b1[j] < 0x10)
									s1 += "0";
								if(b2[j] < 0x10)
									s2 += "0";
								s1 += b1[j].ToString("X");
								s2 += b2[j].ToString("X");
							}
						}
						Console.WriteLine("\t" + (s1 == s2 ? "same" : "diff") + " (" + s1 + " -> " + s2 + ")");
					}
				}
				catch(OverflowException) {}
				catch(NotSupportedException) {}
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
I work for a small software company that builds sales force automation software.

Comments and Discussions