private static void checkNormaliseBaseTenResult(ExpandedDouble orig, NormalisedDecimal result) { String sigDigs = result.getSignificantDecimalDigits(); BigInteger frac = orig.getSignificand(); while (frac.bitLength() + orig.getBinaryExponent() < 200) { frac = frac.multiply(BIG_POW_10); } int binaryExp = orig.getBinaryExponent() - orig.getSignificand().bitLength(); String origDigs = frac.shiftLeft(binaryExp + 1).toString(10); if (!origDigs.startsWith(sigDigs)) { throw new AssertionFailedError("Expected '" + origDigs + "' but got '" + sigDigs + "'."); } double dO = Double.parseDouble("0." + origDigs.substring(sigDigs.length())); double d1 = Double.parseDouble(result.getFractionalPart().toPlainString()); BigInteger subDigsO = BigInteger.valueOf((int) (dO * 32768 + 0.5)); BigInteger subDigsB = BigInteger.valueOf((int) (d1 * 32768 + 0.5)); if (subDigsO.equals(subDigsB)) { return; } BigInteger diff = subDigsB.subtract(subDigsO).abs(); if (diff.intValue() > 100) { // 100/32768 ~= 0.003 throw new AssertionFailedError("minor mistake"); } }
public void testSubnormal() { ExpandedDouble hd = new ExpandedDouble(0x0000000000000001L); if (hd.getBinaryExponent() == -1023) { throw new AssertionFailedError("identified bug - subnormal numbers not decoded properly"); } assertEquals(-1086, hd.getBinaryExponent()); BigInteger frac = hd.getSignificand(); assertEquals(64, frac.bitLength()); assertEquals(1, frac.bitCount()); }
public void testNegative() { ExpandedDouble hd = new ExpandedDouble(0xC010000000000000L); if (hd.getBinaryExponent() == -2046) { throw new AssertionFailedError("identified bug - sign bit not masked out of exponent"); } assertEquals(2, hd.getBinaryExponent()); BigInteger frac = hd.getSignificand(); assertEquals(64, frac.bitLength()); assertEquals(1, frac.bitCount()); }
public static boolean confirmRoundTrip(int i, long rawBitsA) { double a = Double.longBitsToDouble(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 (RuntimeException e) { System.err.println("example[" + i + "] (" + formatDoubleAsHex(a) + ") exception:"); e.printStackTrace(); return false; } if (ed3.getBinaryExponent() != ed1.getBinaryExponent()) { System.err.println("example[" + i + "] (" + formatDoubleAsHex(a) + ") bin exp mismatch"); return false; } BigInteger diff = ed3.getSignificand().subtract(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.bitLength() < 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 System.out.println( "example[" + i + "] (" + formatDoubleAsHex(a) + ") frac mismatch: " + diff.toString()); for (int j = -2; j < 3; j++) { System.out.println((j < 0 ? "" : "+") + j + ": " + getNearby(ed1, j)); } for (int j = -2; j < 3; j++) { System.out.println((j < 0 ? "" : "+") + j + ": " + getNearby(nd2, j)); } return false; }
public static String getBaseDecimal(ExpandedDouble hd) { int gg = 64 - hd.getBinaryExponent() - 1; BigDecimal bd = new BigDecimal(hd.getSignificand()).divide(new BigDecimal(BigInteger.ONE.shiftLeft(gg))); int excessPrecision = bd.precision() - 23; if (excessPrecision > 0) { bd = bd.setScale(bd.scale() - excessPrecision, BigDecimal.ROUND_HALF_UP); } return bd.unscaledValue().toString(); }
public static BigInteger getNearby(ExpandedDouble hd, int offset) { return getNearby(hd.getSignificand(), hd.getBinaryExponent(), offset); }