809N/A/*
3909N/A * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
809N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
809N/A *
809N/A * This code is free software; you can redistribute it and/or modify it
809N/A * under the terms of the GNU General Public License version 2 only, as
809N/A * published by the Free Software Foundation.
809N/A *
809N/A * This code is distributed in the hope that it will be useful, but WITHOUT
809N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
809N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
809N/A * version 2 for more details (a copy is included in the LICENSE file that
809N/A * accompanied this code).
809N/A *
809N/A * You should have received a copy of the GNU General Public License version
809N/A * 2 along with this work; if not, write to the Free Software Foundation,
809N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
809N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
809N/A */
809N/A
809N/A/*
809N/A * @test
4124N/A * @bug 4160406 4705734 4707389 4826774 4895911 4421494 7021568 7039369
809N/A * @summary Test for Double.parseDouble method and acceptance regex
809N/A */
809N/A
809N/Aimport java.util.regex.*;
3502N/Aimport java.math.BigDecimal;
809N/A
809N/Apublic class ParseDouble {
809N/A
809N/A private static void check(String val, double expected) {
809N/A double n = Double.parseDouble(val);
809N/A if (n != expected)
809N/A throw new RuntimeException("Double.parseDouble failed. String:" +
809N/A val + " Result:" + n);
809N/A }
809N/A
809N/A private static void rudimentaryTest() {
809N/A check(new String(""+Double.MIN_VALUE), Double.MIN_VALUE);
809N/A check(new String(""+Double.MAX_VALUE), Double.MAX_VALUE);
809N/A
809N/A check("10", (double) 10.0);
809N/A check("10.0", (double) 10.0);
809N/A check("10.01", (double) 10.01);
809N/A
809N/A check("-10", (double) -10.0);
809N/A check("-10.00", (double) -10.0);
809N/A check("-10.01", (double) -10.01);
809N/A }
809N/A
809N/A
809N/A static String badStrings[] = {
809N/A "",
809N/A "+",
809N/A "-",
809N/A "+e",
809N/A "-e",
809N/A "+e170",
809N/A "-e170",
809N/A
809N/A // Make sure intermediate white space is not deleted.
809N/A "1234 e10",
809N/A "-1234 e10",
809N/A
809N/A // Control characters in the interior of a string are not legal
809N/A "1\u0007e1",
809N/A "1e\u00071",
809N/A
809N/A // NaN and infinity can't have trailing type suffices or exponents
809N/A "NaNf",
809N/A "NaNF",
809N/A "NaNd",
809N/A "NaND",
809N/A "-NaNf",
809N/A "-NaNF",
809N/A "-NaNd",
809N/A "-NaND",
809N/A "+NaNf",
809N/A "+NaNF",
809N/A "+NaNd",
809N/A "+NaND",
809N/A "Infinityf",
809N/A "InfinityF",
809N/A "Infinityd",
809N/A "InfinityD",
809N/A "-Infinityf",
809N/A "-InfinityF",
809N/A "-Infinityd",
809N/A "-InfinityD",
809N/A "+Infinityf",
809N/A "+InfinityF",
809N/A "+Infinityd",
809N/A "+InfinityD",
809N/A
809N/A "NaNe10",
809N/A "-NaNe10",
809N/A "+NaNe10",
809N/A "Infinitye10",
809N/A "-Infinitye10",
809N/A "+Infinitye10",
809N/A
809N/A // Non-ASCII digits are not recognized
809N/A "\u0661e\u0661", // 1e1 in Arabic-Indic digits
809N/A "\u06F1e\u06F1", // 1e1 in Extended Arabic-Indic digits
809N/A "\u0967e\u0967", // 1e1 in Devanagari digits
809N/A
809N/A // JCK test lex03592m3
809N/A ".",
809N/A
809N/A // JCK test lex03592m4
809N/A "e42",
809N/A
809N/A // JCK test lex03592m5
809N/A ".e42",
809N/A
809N/A // JCK test lex03592m6
809N/A "d",
809N/A
809N/A // JCK test lex03592m7
809N/A ".d",
809N/A
809N/A // JCK test lex03592m8
809N/A "e42d",
809N/A
809N/A // JCK test lex03592m9
809N/A ".e42d",
809N/A
809N/A // JCK test lex03593m10
809N/A "1A01.01125e-10d",
809N/A
809N/A // JCK test lex03593m11
809N/A "2;3.01125e-10d",
809N/A
809N/A // JCK test lex03593m12
809N/A "1_34.01125e-10d",
809N/A
809N/A // JCK test lex03593m14
809N/A "202..01125e-10d",
809N/A
809N/A // JCK test lex03593m15
809N/A "202,01125e-10d",
809N/A
809N/A // JCK test lex03593m16
809N/A "202.03b4e-10d",
809N/A
809N/A // JCK test lex03593m18
809N/A "202.06_3e-10d",
809N/A
809N/A // JCK test lex03593m20
809N/A "202.01125e-f0d",
809N/A
809N/A // JCK test lex03593m21
809N/A "202.01125e_3d",
809N/A
809N/A // JCK test lex03593m22
809N/A "202.01125e -5d",
809N/A
809N/A // JCK test lex03593m24
809N/A "202.01125e-10r",
809N/A
809N/A // JCK test lex03593m25
809N/A "202.01125e-10ff",
809N/A
809N/A // JCK test lex03593m26
809N/A "1234L.01",
809N/A
809N/A // JCK test lex03593m27
809N/A "12ee-2",
809N/A
809N/A // JCK test lex03593m28
809N/A "12e-2.2.2",
809N/A
809N/A // JCK test lex03593m29
809N/A "12.01e+",
809N/A
809N/A // JCK test lex03593m30
809N/A "12.01E",
809N/A
809N/A // Bad hexadecimal-style strings
809N/A
809N/A // Two leading zeros
809N/A "00x1.0p1",
809N/A
809N/A // Must have hex specifier
809N/A "1.0p1",
809N/A "00010p1",
809N/A "deadbeefp1",
809N/A
809N/A // Need an explicit fully-formed exponent
809N/A "0x1.0p",
809N/A "0x1.0",
809N/A
809N/A // Exponent must be in decimal
809N/A "0x1.0pa",
809N/A "0x1.0pf",
809N/A
809N/A // Exponent separated by "p"
809N/A "0x1.0e22",
809N/A "0x1.0e22",
809N/A
809N/A // Need a signifcand
809N/A "0xp22"
809N/A };
809N/A
809N/A static String goodStrings[] = {
809N/A "NaN",
809N/A "+NaN",
809N/A "-NaN",
809N/A "Infinity",
809N/A "+Infinity",
809N/A "-Infinity",
809N/A "1.1e-23f",
809N/A ".1e-23f",
809N/A "1e-23",
809N/A "1f",
809N/A "0",
809N/A "-0",
809N/A "+0",
809N/A "00",
809N/A "00",
809N/A "-00",
809N/A "+00",
809N/A "0000000000",
809N/A "-0000000000",
809N/A "+0000000000",
809N/A "1",
809N/A "2",
809N/A "1234",
809N/A "-1234",
809N/A "+1234",
809N/A "2147483647", // Integer.MAX_VALUE
809N/A "2147483648",
809N/A "-2147483648", // Integer.MIN_VALUE
809N/A "-2147483649",
809N/A
809N/A "16777215",
809N/A "16777216", // 2^24
809N/A "16777217",
809N/A
809N/A "-16777215",
809N/A "-16777216", // -2^24
809N/A "-16777217",
809N/A
809N/A "9007199254740991",
809N/A "9007199254740992", // 2^53
809N/A "9007199254740993",
809N/A
809N/A "-9007199254740991",
809N/A "-9007199254740992", // -2^53
809N/A "-9007199254740993",
809N/A
809N/A "9223372036854775807",
809N/A "9223372036854775808", // Long.MAX_VALUE
809N/A "9223372036854775809",
809N/A
809N/A "-9223372036854775808",
809N/A "-9223372036854775809", // Long.MIN_VALUE
809N/A "-9223372036854775810",
809N/A
809N/A // Culled from JCK test lex03591m1
809N/A "54.07140d",
809N/A "7.01e-324d",
809N/A "2147483647.01d",
809N/A "1.2147483647f",
809N/A "000000000000000000000000001.F",
809N/A "1.00000000000000000000000000e-2F",
809N/A
809N/A // Culled from JCK test lex03592m2
809N/A "2.",
809N/A ".0909",
809N/A "122112217090.0",
809N/A "7090e-5",
809N/A "2.E-20",
809N/A ".0909e42",
809N/A "122112217090.0E+100",
809N/A "7090f",
809N/A "2.F",
809N/A ".0909d",
809N/A "122112217090.0D",
809N/A "7090e-5f",
809N/A "2.E-20F",
809N/A ".0909e42d",
809N/A "122112217090.0E+100D",
809N/A
809N/A // Culled from JCK test lex03594m31 -- unicode escapes
809N/A "\u0035\u0031\u0034\u0039\u0032\u0033\u0036\u0037\u0038\u0030.1102E-209D",
809N/A "1290873\u002E12301e100",
809N/A "1.1E-10\u0066",
809N/A
809N/A // Culled from JCK test lex03595m1
809N/A "0.0E-10",
809N/A "1E10",
809N/A
809N/A // Culled from JCK test lex03691m1
809N/A "0.f",
809N/A "1f",
809N/A "0.F",
809N/A "1F",
809N/A "0.12d",
809N/A "1e-0d",
809N/A "12.e+1D",
809N/A "0e-0D",
809N/A "12.e+01",
809N/A "1e-01",
809N/A
809N/A // Good hex strings
809N/A // Vary capitalization of separators.
809N/A
809N/A "0x1p1",
809N/A "0X1p1",
809N/A "0x1P1",
809N/A "0X1P1",
809N/A "0x1p1f",
809N/A "0X1p1f",
809N/A "0x1P1f",
809N/A "0X1P1f",
809N/A "0x1p1F",
809N/A "0X1p1F",
809N/A "0x1P1F",
809N/A "0X1P1F",
809N/A "0x1p1d",
809N/A "0X1p1d",
809N/A "0x1P1d",
809N/A "0X1P1d",
809N/A "0x1p1D",
809N/A "0X1p1D",
809N/A "0x1P1D",
809N/A "0X1P1D",
809N/A
809N/A "-0x1p1",
809N/A "-0X1p1",
809N/A "-0x1P1",
809N/A "-0X1P1",
809N/A "-0x1p1f",
809N/A "-0X1p1f",
809N/A "-0x1P1f",
809N/A "-0X1P1f",
809N/A "-0x1p1F",
809N/A "-0X1p1F",
809N/A "-0x1P1F",
809N/A "-0X1P1F",
809N/A "-0x1p1d",
809N/A "-0X1p1d",
809N/A "-0x1P1d",
809N/A "-0X1P1d",
809N/A "-0x1p1D",
809N/A "-0X1p1D",
809N/A "-0x1P1D",
809N/A "-0X1P1D",
809N/A
809N/A "0x1p-1",
809N/A "0X1p-1",
809N/A "0x1P-1",
809N/A "0X1P-1",
809N/A "0x1p-1f",
809N/A "0X1p-1f",
809N/A "0x1P-1f",
809N/A "0X1P-1f",
809N/A "0x1p-1F",
809N/A "0X1p-1F",
809N/A "0x1P-1F",
809N/A "0X1P-1F",
809N/A "0x1p-1d",
809N/A "0X1p-1d",
809N/A "0x1P-1d",
809N/A "0X1P-1d",
809N/A "0x1p-1D",
809N/A "0X1p-1D",
809N/A "0x1P-1D",
809N/A "0X1P-1D",
809N/A
809N/A "-0x1p-1",
809N/A "-0X1p-1",
809N/A "-0x1P-1",
809N/A "-0X1P-1",
809N/A "-0x1p-1f",
809N/A "-0X1p-1f",
809N/A "-0x1P-1f",
809N/A "-0X1P-1f",
809N/A "-0x1p-1F",
809N/A "-0X1p-1F",
809N/A "-0x1P-1F",
809N/A "-0X1P-1F",
809N/A "-0x1p-1d",
809N/A "-0X1p-1d",
809N/A "-0x1P-1d",
809N/A "-0X1P-1d",
809N/A "-0x1p-1D",
809N/A "-0X1p-1D",
809N/A "-0x1P-1D",
809N/A "-0X1P-1D",
809N/A
809N/A
809N/A // Try different significand combinations
809N/A "0xap1",
809N/A "0xbp1",
809N/A "0xcp1",
809N/A "0xdp1",
809N/A "0xep1",
809N/A "0xfp1",
809N/A
809N/A "0x1p1",
809N/A "0x.1p1",
809N/A "0x1.1p1",
809N/A
809N/A "0x001p23",
809N/A "0x00.1p1",
809N/A "0x001.1p1",
809N/A
809N/A "0x100p1",
809N/A "0x.100p1",
809N/A "0x1.100p1",
809N/A
809N/A "0x00100p1",
809N/A "0x00.100p1",
3502N/A "0x001.100p1",
3502N/A
3502N/A // Limits
3502N/A
3502N/A "1.7976931348623157E308", // Double.MAX_VALUE
3502N/A "4.9e-324", // Double.MIN_VALUE
3502N/A "2.2250738585072014e-308", // Double.MIN_NORMAL
3502N/A
3502N/A "2.2250738585072012e-308", // near Double.MIN_NORMAL
809N/A };
809N/A
809N/A static String paddedBadStrings[];
809N/A static String paddedGoodStrings[];
809N/A static {
809N/A String pad = " \t\n\r\f\u0001\u000b\u001f";
809N/A paddedBadStrings = new String[badStrings.length];
809N/A for(int i = 0 ; i < badStrings.length; i++)
809N/A paddedBadStrings[i] = pad + badStrings[i] + pad;
809N/A
809N/A paddedGoodStrings = new String[goodStrings.length];
809N/A for(int i = 0 ; i < goodStrings.length; i++)
809N/A paddedGoodStrings[i] = pad + goodStrings[i] + pad;
809N/A
809N/A }
809N/A
809N/A
809N/A /*
809N/A * Throws an exception if <code>Input</code> is
809N/A * <code>exceptionalInput</code> and {@link Double.parseDouble
809N/A * parseDouble} does <em>not</em> throw an exception or if
809N/A * <code>Input</code> is not <code>exceptionalInput</code> and
809N/A * <code>parseDouble</code> throws an exception. This method does
809N/A * not attempt to test whether the string is converted to the
809N/A * proper value; just whether the input is accepted appropriately
809N/A * or not.
809N/A */
809N/A private static void testParsing(String [] input,
809N/A boolean exceptionalInput) {
809N/A for(int i = 0; i < input.length; i++) {
809N/A double d;
809N/A
809N/A try {
809N/A d = Double.parseDouble(input[i]);
809N/A }
809N/A catch (NumberFormatException e) {
809N/A if (! exceptionalInput) {
809N/A throw new RuntimeException("Double.parseDouble rejected " +
809N/A "good string `" + input[i] +
809N/A "'.");
809N/A }
809N/A break;
809N/A }
809N/A if (exceptionalInput) {
809N/A throw new RuntimeException("Double.parseDouble accepted " +
809N/A "bad string `" + input[i] +
809N/A "'.");
809N/A }
809N/A }
809N/A }
809N/A
809N/A /*
809N/A * Throws an exception if <code>Input</code> is
809N/A * <code>exceptionalInput</code> and the regular expression
809N/A * matches one of the strings or if <code>Input</code> is not
809N/A * <code>exceptionalInput</code> and the regular expression fails
809N/A * to match an input string.
809N/A */
809N/A private static void testRegex(String [] input, boolean exceptionalInput) {
809N/A /*
809N/A * The regex below is taken from the JavaDoc for
809N/A * Double.valueOf.
809N/A */
809N/A
809N/A final String Digits = "(\\p{Digit}+)";
809N/A final String HexDigits = "(\\p{XDigit}+)";
809N/A // an exponent is 'e' or 'E' followed by an optionally
809N/A // signed decimal integer.
809N/A final String Exp = "[eE][+-]?"+Digits;
809N/A final String fpRegex =
809N/A ("[\\x00-\\x20]*"+ // Optional leading "whitespace"
809N/A "[+-]?(" + // Optional sign character
809N/A "NaN|" + // "NaN" string
809N/A "Infinity|" + // "Infinity" string
809N/A
809N/A // A floating-point string representing a finite positive
809N/A // number without a leading sign has at most five basic pieces:
809N/A // Digits . Digits ExponentPart FloatTypeSuffix
809N/A //
809N/A // Since this method allows integer-only strings as input
809N/A // in addition to strings of floating-point literals, the
809N/A // two sub-patterns below are simplifications of the grammar
809N/A // productions from the Java Language Specification, 2nd
809N/A // edition, section 3.10.2.
809N/A
809N/A
809N/A // A decimal floating-point string representing a finite positive
809N/A // number without a leading sign has at most five basic pieces:
809N/A // Digits . Digits ExponentPart FloatTypeSuffix
809N/A //
809N/A // Since this method allows integer-only strings as input
809N/A // in addition to strings of floating-point literals, the
809N/A // two sub-patterns below are simplifications of the grammar
809N/A // productions from the Java Language Specification, 2nd
809N/A // edition, section 3.10.2.
809N/A
809N/A // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
809N/A "(((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
809N/A
809N/A // . Digits ExponentPart_opt FloatTypeSuffix_opt
809N/A "(\\.("+Digits+")("+Exp+")?))|"+
809N/A
809N/A // Hexadecimal strings
809N/A "((" +
809N/A // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
809N/A "(0[xX]" + HexDigits + "(\\.)?)|" +
809N/A
809N/A // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
809N/A "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
809N/A
809N/A ")[pP][+-]?" + Digits + "))" +
809N/A "[fFdD]?))" +
809N/A "[\\x00-\\x20]*");// Optional trailing "whitespace"
809N/A Pattern fpPattern = Pattern.compile(fpRegex);
809N/A
809N/A for(int i = 0; i < input.length; i++) {
809N/A Matcher m = fpPattern.matcher(input[i]);
809N/A if (m.matches() != ! exceptionalInput) {
809N/A throw new RuntimeException("Regular expression " +
809N/A (exceptionalInput?
809N/A "accepted bad":
809N/A "rejected good") +
809N/A " string `" +
809N/A input[i] + "'.");
809N/A }
809N/A }
809N/A
809N/A }
809N/A
3502N/A /**
3502N/A * For each subnormal power of two, test at boundaries of
3502N/A * region that should convert to that value.
3502N/A */
3502N/A private static void testSubnormalPowers() {
3502N/A BigDecimal TWO = BigDecimal.valueOf(2);
3502N/A // An ulp is the same for all subnormal values
3502N/A BigDecimal ulp_BD = new BigDecimal(Double.MIN_VALUE);
3502N/A
3502N/A // Test subnormal powers of two
3502N/A for(int i = -1074; i <= -1022; i++) {
3502N/A double d = Math.scalb(1.0, i);
3502N/A
3502N/A /*
3502N/A * The region [d - ulp/2, d + ulp/2] should round to d.
3502N/A */
3502N/A BigDecimal d_BD = new BigDecimal(d);
3502N/A
3502N/A BigDecimal lowerBound = d_BD.subtract(ulp_BD.divide(TWO));
3502N/A BigDecimal upperBound = d_BD.add(ulp_BD.divide(TWO));
3502N/A
3502N/A double convertedLowerBound = Double.parseDouble(lowerBound.toString());
3502N/A double convertedUpperBound = Double.parseDouble(upperBound.toString());
3502N/A }
3502N/A }
3502N/A
4018N/A
4018N/A private static void testStrictness() {
4018N/A final double expected = 0x0.0000008000001p-1022;
4018N/A boolean failed = false;
4018N/A double conversion = 0.0;
4018N/A double sum = 0.0; // Prevent conversion from being optimized away
4018N/A
4018N/A //2^-1047 + 2^-1075
4018N/A String decimal = "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316";
4018N/A
4018N/A for(int i = 0; i <= 12_000; i++) {
4018N/A conversion = Double.parseDouble(decimal);
4018N/A sum += conversion;
4018N/A if (conversion != expected) {
4018N/A failed = true;
4018N/A System.out.printf("Iteration %d converts as %a%n",
4018N/A i, conversion);
4018N/A }
4018N/A }
4018N/A
4018N/A System.out.println("Sum = " + sum);
4018N/A if (failed)
4018N/A throw new RuntimeException("Inconsistent conversion");
4018N/A }
4018N/A
809N/A public static void main(String[] args) throws Exception {
809N/A rudimentaryTest();
809N/A
809N/A testParsing(goodStrings, false);
809N/A testParsing(paddedGoodStrings, false);
809N/A testParsing(badStrings, true);
809N/A testParsing(paddedBadStrings, true);
809N/A
809N/A testRegex(goodStrings, false);
809N/A testRegex(paddedGoodStrings, false);
809N/A testRegex(badStrings, true);
809N/A testRegex(paddedBadStrings, true);
3502N/A
3502N/A testSubnormalPowers();
4018N/A testStrictness();
809N/A }
809N/A}