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) {}
}
}
}
}