Index: luni/src/test/java/org/apache/harmony/luni/tests/java/lang/FloatTest.java =================================================================== --- luni/src/test/java/org/apache/harmony/luni/tests/java/lang/FloatTest.java (revision 431327) +++ luni/src/test/java/org/apache/harmony/luni/tests/java/lang/FloatTest.java (working copy) @@ -126,6 +126,28 @@ Float f = new Float("900.89"); assertTrue("Created incorrect Float", f.floatValue() == 900.89f); + + // Test hexadecimal values + Float f1 = new Float("0x0.0p0"); + assertEquals(f1, new Float(0.0)); + f1 = new Float("-0x0.0p0"); + assertEquals(f1, new Float(-0.0)); + f1 = new Float("0x1.0p0"); + assertEquals(f1, new Float(1.0)); + f1 = new Float("-0x1.0p0"); + assertEquals(f1, new Float(-1.0)); + f1 = new Float("0x1.0p1"); + assertEquals(f1, new Float(2.0)); + f1 = new Float("0x1.8p1"); + assertEquals(f1, new Float(3.0)); + f1 = new Float("0x1.0p-1"); + assertEquals(f1, new Float(0.5)); + f1 = new Float("0x1.0p-2"); + assertEquals(f1, new Float(0.25)); + f1 = new Float("0x1.fffffep127"); + assertEquals(f1, new Float(Float.MAX_VALUE)); + f1 = new Float("0x0.000002p-126"); + assertEquals(f1, new Float(Float.MIN_VALUE)); } /** @@ -421,6 +443,37 @@ doTestCompareRawBits("1.0E+39", 0x7f800000, "Infinity"); doTestCompareRawBits("-1.0E+39", 0xff800000, "-Infinity"); + /* + * Test hexadecimal input + */ + // Values from the javadoc + doTestCompareRawBits("0x0.0p0", 0, "0.0"); + doTestCompareRawBits("-0x0.0p0", 0x80000000, "-0.0"); + doTestCompareRawBits("0x1.0p0", 0x3f800000, "1.0"); + doTestCompareRawBits("-0x1.0p0", 0xbf800000, "-1.0"); + doTestCompareRawBits("0x1.0p1", 0x40000000, "2.0"); + doTestCompareRawBits("0x1.8p1", 0x40400000, "3.0"); + doTestCompareRawBits("0x1.0p-1", 0x3f000000, "0.5"); + doTestCompareRawBits("0x1.0p-2", 0x3e800000, "0.25"); + doTestCompareRawBits("0x1.fffffep127", 0x7f7fffff, "3.4028235E38"); // Float.MAX_VALUE + doTestCompareRawBits("0x0.000002p-126", 0x1, "1.4E-45"); // Float.MIN_VALUE + + // Various values + doTestCompareRawBits("0x1.ecp6", 0x42f60000, "123.0"); + doTestCompareRawBits("-0x1.da8p6", 0xc2ed4000, "-118.625"); + doTestCompareRawBits("0x1.295788p23", 0x4b14abc4, "9743300.0"); + doTestCompareRawBits("0x1.700d1p33", 0x50380688, "1.2349743E10"); + + // Capital X + doTestCompareRawBits("0X1.ecp6", 0x42f60000, "123.0"); + + // '+' at the start + doTestCompareRawBits("+0x1.ecp6", 0x42f60000, "123.0"); + + // F at the end + doTestCompareRawBits("0x1.ecp6f", 0x42f60000, "123.0"); + doTestCompareRawBits("0x1.ecp6F", 0x42f60000, "123.0"); + if (compareResults != null) { StringBuffer failString = new StringBuffer(); for (int i = 0; i < compareResults.size(); i++) { @@ -538,6 +591,28 @@ Float negInfiniteSigned = Float.valueOf("-Infinity"); assertTrue("Floattest7", negInfiniteSigned.equals(new Float(Float.NEGATIVE_INFINITY))); + + // Tests for hexadecimal values + Float f1 = Float.valueOf("0x0.0p0"); + assertEquals("Floattest8", f1, new Float(0.0)); + f1 = Float.valueOf("-0x0.0p0"); + assertEquals("Floattest9", f1, new Float(-0.0)); + f1 = Float.valueOf("0x1.0p0"); + assertEquals("Floattest10", f1, new Float(1.0)); + f1 = Float.valueOf("-0x1.0p0"); + assertEquals("Floattest11", f1, new Float(-1.0)); + f1 = Float.valueOf("0x1.0p1"); + assertEquals("Floattest12", f1, new Float(2.0)); + f1 = Float.valueOf("0x1.8p1"); + assertEquals("Floattest13", f1, new Float(3.0)); + f1 = Float.valueOf("0x1.0p-1"); + assertEquals("Floattest14", f1, new Float(0.5)); + f1 = Float.valueOf("0x1.0p-2"); + assertEquals("Floattest15", f1, new Float(0.25)); + f1 = Float.valueOf("0x1.fffffep127"); + assertEquals("Floattest16", f1, new Float(Float.MAX_VALUE)); + f1 = Float.valueOf("0x0.000002p-126"); + assertEquals("Floattest17", f1, new Float(Float.MIN_VALUE)); } private void test_toString(float ff, String answer) { Index: luni/src/test/java/org/apache/harmony/luni/tests/java/lang/DoubleTest.java =================================================================== --- luni/src/test/java/org/apache/harmony/luni/tests/java/lang/DoubleTest.java (revision 431327) +++ luni/src/test/java/org/apache/harmony/luni/tests/java/lang/DoubleTest.java (working copy) @@ -258,6 +258,28 @@ } catch (NumberFormatException e) { // expected } + + // Tests for hexadecimal values + Double d1 = new Double("0x0.0p0"); + assertEquals(d1, new Double(0.0)); + d1 = new Double("-0x0.0p0"); + assertEquals(d1, new Double(-0.0)); + d1 = new Double("0x1.0p0"); + assertEquals(d1, new Double(1.0)); + d1 = new Double("-0x1.0p0"); + assertEquals(d1, new Double(-1.0)); + d1 = new Double("0x1.0p1"); + assertEquals(d1, new Double(2.0)); + d1 = new Double("0x1.8p1"); + assertEquals(d1, new Double(3.0)); + d1 = new Double("0x1.0p-1"); + assertEquals( d1, new Double(0.5)); + d1 = new Double("0x1.0p-2"); + assertEquals(d1, new Double(0.25)); + d1 = new Double("0x1.fffffffffffffp1023"); + assertEquals(d1, new Double(Double.MAX_VALUE)); + d1 = new Double("0x0.0000000000001p-1022"); + assertEquals(d1, new Double(Double.MIN_VALUE)); } /** @@ -587,6 +609,39 @@ "-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055595409854908458349204328908234982349050934129878452378432452458968024357823490509341298784523784324524589680243578234905093412987845237843245245896802435782349050934129878452378432452458968024357868024357823490509341298784523784324524589680243578234905093412987845237843245245896802435786802435782349050934129878452378432452458968024357823490509341298784523784324524589680243578", 0x8000000000000001L, "-4.9E-324"); + /* + * Test hexadecimal format input + */ + + // Values from the javadoc + doTestCompareRawBits("0x0.0p0", 0L, "0.0"); + doTestCompareRawBits("-0x0.0p0", 0x8000000000000000L, "-0.0"); + doTestCompareRawBits("0x1.0p0", 0x3ff0000000000000L, "1.0"); + doTestCompareRawBits("-0x1.0p0", 0xbff0000000000000L, "-1.0"); + doTestCompareRawBits("0x1.0p1", 0x4000000000000000L, "2.0"); + doTestCompareRawBits("0x1.8p1", 0x4008000000000000L, "3.0"); + doTestCompareRawBits("0x1.0p-1", 0x3fe0000000000000L, "0.5"); + doTestCompareRawBits("0x1.0p-2", 0x3fd0000000000000L, "0.25"); + doTestCompareRawBits("0x1.fffffffffffffp1023", 0x7fefffffffffffffL, "1.7976931348623157E308"); // Double.MAX_VALUE + doTestCompareRawBits("0x0.0000000000001p-1022", 1L, "4.9E-324"); // Double.MIN_VALUE + + // Various values + doTestCompareRawBits("0x1.ecp6", 0x405ec00000000000L, "123.0"); + doTestCompareRawBits("-0x1.da8p6", 0xc05da80000000000L, "-118.625"); + doTestCompareRawBits("0x1.2957874cccccdp23", 0x4162957874cccccdL, "9743299.65"); + doTestCompareRawBits("0x1.2957874cccf63p23", 0x4162957874cccf63L, "9743299.650001233"); + doTestCompareRawBits("0x1.700d1061d3333p33", 0x420700d1061d3333L, "1.234974329965E10"); + + // Capital X + doTestCompareRawBits("0X1.ecp6", 0x405ec00000000000L, "123.0"); + + // '+' on the start + doTestCompareRawBits("+0x1.ecp6", 0x405ec00000000000L, "123.0"); + + // D on the end + doTestCompareRawBits("0x1.ecp6D", 0x405ec00000000000L, "123.0"); + doTestCompareRawBits("0x1.ecp6d", 0x405ec00000000000L, "123.0"); + verifyStaticTests(); } @@ -751,6 +806,28 @@ Double negInfiniteSigned = Double.valueOf("-Infinity"); assertTrue("Doubletest6", negInfiniteSigned .equals(new Double(Double.NEGATIVE_INFINITY))); + + // Tests for hexadecimal values + Double d1 = Double.valueOf("0x0.0p0"); + assertEquals("Doubletest7", d1, new Double(0.0)); + d1 = Double.valueOf("-0x0.0p0"); + assertEquals("Doubletest8", d1, new Double(-0.0)); + d1 = Double.valueOf("0x1.0p0"); + assertEquals("Doubletest9", d1, new Double(1.0)); + d1 = Double.valueOf("-0x1.0p0"); + assertEquals("Doubletest10", d1, new Double(-1.0)); + d1 = Double.valueOf("0x1.0p1"); + assertEquals("Doubletest11", d1, new Double(2.0)); + d1 = Double.valueOf("0x1.8p1"); + assertEquals("Doubletest12", d1, new Double(3.0)); + d1 = Double.valueOf("0x1.0p-1"); + assertEquals("Doubletest13", d1, new Double(0.5)); + d1 = Double.valueOf("0x1.0p-2"); + assertEquals("Doubletest14", d1, new Double(0.25)); + d1 = Double.valueOf("0x1.fffffffffffffp1023"); + assertEquals("Doubletest15", d1, new Double(Double.MAX_VALUE)); + d1 = Double.valueOf("0x0.0000000000001p-1022"); + assertEquals("Doubletest16", d1, new Double(Double.MIN_VALUE)); } /** Index: luni/src/main/java/org/apache/harmony/luni/util/FloatingPointParser.java =================================================================== --- luni/src/main/java/org/apache/harmony/luni/util/FloatingPointParser.java (revision 431327) +++ luni/src/main/java/org/apache/harmony/luni/util/FloatingPointParser.java (working copy) @@ -173,6 +173,220 @@ return new StringExponentPair(s, e, negative); } + /** + * Takes a String in hexadecimal format (e.g. as produced by Double.toHexValue) + * and parses it to a floating point number + * @param s + * the String that will be parsed to a floating point + * @param length + * the length of s + * @return a Double + * + * @exception NumberFormatException + * if the String doesn't pass basic tests + */ + private static Double parseDblFromHex(String s, int length) { + boolean negative = false; + char c; + int start = 0, end; + long e = 0; + + start = 0; + if (length == 0) + throw new NumberFormatException(s); + + c = s.charAt(length - 1); + if (c == 'D' || c == 'd' || c == 'F' || c == 'f') { + length--; + if (length == 0) + throw new NumberFormatException(s); + } + + end = Math.max(s.indexOf('P'), s.indexOf('p')); + if (end > -1) { + if (end + 1 == length) + throw new NumberFormatException(s); + + int exponent_offset = end + 1; + if (s.charAt(exponent_offset) == '+') { + if (s.charAt(exponent_offset + 1) == '-') { + throw new NumberFormatException(s); + } + exponent_offset++; // skip the plus sign + } + try { + e = Long.parseLong(s.substring(exponent_offset, length)); + } catch (NumberFormatException ex) { + // ex contains the exponent substring + // only so throw a new exception with + // the correct string + throw new NumberFormatException(s); + } + } else { + end = length; + } + + if (length == 0) + throw new NumberFormatException(s); + + c = s.charAt(start); + if (c == '-') { + ++start; + --length; + negative = true; + } else if (c == '+') { + ++start; + --length; + } + if (length == 0) + throw new NumberFormatException(s); + + long normalDigit = Long.valueOf(String.valueOf(s.charAt(start + 2))); + if(normalDigit != 0 && normalDigit != 1) { + throw new NumberFormatException(s); + } + + boolean normal = normalDigit == 1; + + // Bias the exponent + if(normal) { + e = e + 1023; + } else { + e = 0; + } + + // Move the start position past "0x0." or "0x1." so it's now pointing to the + // first digit of the significand + start += 4; + + String significandStr = s.substring(start, end); + + long significand = Long.valueOf(significandStr, 16); + + // Aiming for 13 hex digits (52 bits) so we need to fill in some zeros + int significandDigits = significandStr.length(); + while (significandDigits < 13) { + significand <<= 4; + significandDigits++; + } + + // Add the exponent + long bitValue = significand | e << 52; + + // Add the negative bit if required + if(negative) { + bitValue |= 0x8000000000000000L; + } + return Double.longBitsToDouble(bitValue); + } + + /** + * Takes a String in hexadecimal format (e.g. as produced by Float.toHexValue) + * and parses it to a floating point number + * @param s + * the String that will be parsed to a floating point + * @param length + * the length of s + * @return a Float + * + * @exception NumberFormatException + * if the String doesn't pass basic tests + */ + private static Float parseFltFromHex(String s, int length) { + boolean negative = false; + char c; + int start = 0, end; + int e = 0; + + start = 0; + if (length == 0) + throw new NumberFormatException(s); + + c = s.charAt(length - 1); + if (c == 'D' || c == 'd' || c == 'F' || c == 'f') { + length--; + if (length == 0) + throw new NumberFormatException(s); + } + + end = Math.max(s.indexOf('P'), s.indexOf('p')); + if (end > -1) { + if (end + 1 == length) + throw new NumberFormatException(s); + + int exponent_offset = end + 1; + if (s.charAt(exponent_offset) == '+') { + if (s.charAt(exponent_offset + 1) == '-') { + throw new NumberFormatException(s); + } + exponent_offset++; // skip the plus sign + } + try { + e = Integer.parseInt(s.substring(exponent_offset, length)); + } catch (NumberFormatException ex) { + // ex contains the exponent substring + // only so throw a new exception with + // the correct string + throw new NumberFormatException(s); + } + } else { + end = length; + } + + if (length == 0) + throw new NumberFormatException(s); + + c = s.charAt(start); + if (c == '-') { + ++start; + --length; + negative = true; + } else if (c == '+') { + ++start; + --length; + } + if (length == 0) + throw new NumberFormatException(s); + + long normalDigit = Integer.valueOf(String.valueOf(s.charAt(start + 2))); + if(normalDigit != 0 && normalDigit != 1) { + throw new NumberFormatException(s); + } + boolean normal = normalDigit == 1; + + // Bias the exponent + if(normal) { + e = e + 127; + } else { + e = 0; + } + + // Move the start position past "0x0." or "0x1." so it's now pointing to the + // first digit of the significand + start += 4; + + String significandStr = s.substring(start, end); + + int significand = Integer.valueOf(significandStr, 16); + + int significandDigits = significandStr.length(); + // Aiming for 6 hex digits (23 bits) so we need to fill in some zeros + while (significandDigits < 6) { + significand <<= 4; + significandDigits++; + } + significand >>= 1; // Right shift 1 because it's 23 bits and not 24 + + // Add the exponent + int bitValue = significand | e << 23; + + // Add the negative bit if required + if(negative) { + bitValue |= 0x80000000; + } + return Float.intBitsToFloat(bitValue); + } + /* * Assumes the string is trimmed. */ @@ -259,6 +473,12 @@ if ((last == 'y') || (last == 'N')) { return parseDblName(s, length); } + + // See if this could be a hexadecimal representation + if(s.toLowerCase().indexOf("0x") != -1) { + return parseDblFromHex(s, length); + } + StringExponentPair info = initialParse(s, length); double result = parseDblImpl(info.s, info.e); @@ -291,6 +511,12 @@ if ((last == 'y') || (last == 'N')) { return parseFltName(s, length); } + + // See if this could be a hexadecimal representation + if(s.toLowerCase().indexOf("0x") != -1) { + return parseFltFromHex(s, length); + } + StringExponentPair info = initialParse(s, length); float result = parseFltImpl(info.s, info.e);