public void TestSubnormal() { ExpandedDouble hd = new ExpandedDouble(0x0000000000000001L); if (hd.GetBinaryExponent() == -1023) { throw new AssertionException("identified bug - subnormal numbers not decoded properly"); } Assert.AreEqual(-1086, hd.GetBinaryExponent()); BigInteger frac = hd.GetSignificand(); Assert.AreEqual(64, frac.BitLength()); Assert.AreEqual(1, frac.BitCount()); }
public void TestNegative() { ExpandedDouble hd = new ExpandedDouble(unchecked((long)0xC010000000000000L)); if (hd.GetBinaryExponent() == -2046) { throw new AssertionException("identified bug - sign bit not masked out of exponent"); } Assert.AreEqual(2, hd.GetBinaryExponent()); BigInteger frac = hd.GetSignificand(); Assert.AreEqual(64, frac.BitLength()); Assert.AreEqual(1, frac.BitCount()); }
public static bool ConfirmRoundTrip(int i, long rawBitsA) { double a = BitConverter.Int64BitsToDouble(rawBitsA); if (a == 0.0) { // Can't represent 0.0 or -0.0 with NormalisedDecimal return true; } ExpandedDouble ed1; NormalisedDecimal nd2; ExpandedDouble ed3; try { ed1 = new ExpandedDouble(rawBitsA); nd2 = ed1.NormaliseBaseTen(); CheckNormaliseBaseTenResult(ed1, nd2); ed3 = nd2.NormaliseBaseTwo(); } catch (Exception e) { Console.WriteLine("example[" + i + "] (" + FormatDoubleAsHex(a) + ") exception: " + e.Message); return false; } if (ed3.GetBinaryExponent() != ed1.GetBinaryExponent()) { Console.WriteLine("example[" + i + "] (" + FormatDoubleAsHex(a) + ") bin exp mismatch"); return false; } BigInteger diff = ed3.GetSignificand() - (ed1.GetSignificand()).Abs(); if (diff.Signum() == 0) { return true; } // original quantity only has 53 bits of precision // these quantities may have errors in the 64th bit, which hopefully don't make any difference if (diff.BitCount() < 2) { // errors in the 64th bit happen from time to time // this is well below the 53 bits of precision required return true; } // but bigger errors are a concern Console.WriteLine("example[" + i + "] (" + FormatDoubleAsHex(a) + ") frac mismatch: " + diff.ToString()); for (int j = -2; j < 3; j++) { Console.WriteLine((j < 0 ? "" : "+") + j + ": " + GetNearby(ed1, j)); } for (int j = -2; j < 3; j++) { Console.WriteLine((j < 0 ? "" : "+") + j + ": " + GetNearby(nd2, j)); } return false; }
private static void CheckNormaliseBaseTenResult(ExpandedDouble orig, NormalisedDecimal result) { String sigDigs = result.GetSignificantDecimalDigits(); BigInteger frac = orig.GetSignificand(); while (frac.BitLength() + orig.GetBinaryExponent() < 200) { frac = frac * (BIG_POW_10); } int binaryExp = orig.GetBinaryExponent() - orig.GetSignificand().BitLength(); String origDigs = (frac << (binaryExp + 1)).ToString(10); if (!origDigs.StartsWith(sigDigs)) { throw new AssertionException("Expected '" + origDigs + "' but got '" + sigDigs + "'."); } double dO = Double.Parse("0." + origDigs.Substring(sigDigs.Length)); double d1 = Double.Parse(result.GetFractionalPart().ToString()); BigInteger subDigsO = new BigInteger((int)(dO * 32768 + 0.5)); BigInteger subDigsB = new BigInteger((int)(d1 * 32768 + 0.5)); if (subDigsO.Equals(subDigsB)) { return; } BigInteger diff = (subDigsB - subDigsO).Abs(); if (diff.IntValue() > 100) { // 100/32768 ~= 0.003 throw new AssertionException("minor mistake"); } }
public static BigInteger GetNearby(ExpandedDouble hd, int offset) { return GetNearby(hd.GetSignificand(), hd.GetBinaryExponent(), offset); }