Path: blob/master/test/jdk/java/lang/Double/ParseDouble.java
41149 views
/*1* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 4160406 4705734 4707389 4826774 4895911 4421494 6358355 7021568 7039369 439627226* @summary Test for Double.parseDouble method and acceptance regex27*/2829import java.math.BigDecimal;30import java.math.BigInteger;31import java.util.regex.*;3233public class ParseDouble {3435private static final BigDecimal HALF = BigDecimal.valueOf(0.5);3637private static void fail(String val, double n) {38throw new RuntimeException("Double.parseDouble failed. String:" +39val + " Result:" + n);40}4142private static void check(String val) {43double n = Double.parseDouble(val);44boolean isNegativeN = n < 0 || n == 0 && 1/n < 0;45double na = Math.abs(n);46String s = val.trim().toLowerCase();47switch (s.charAt(s.length() - 1)) {48case 'd':49case 'f':50s = s.substring(0, s.length() - 1);51break;52}53boolean isNegative = false;54if (s.charAt(0) == '+') {55s = s.substring(1);56} else if (s.charAt(0) == '-') {57s = s.substring(1);58isNegative = true;59}60if (s.equals("nan")) {61if (!Double.isNaN(n)) {62fail(val, n);63}64return;65}66if (Double.isNaN(n)) {67fail(val, n);68}69if (isNegativeN != isNegative)70fail(val, n);71if (s.equals("infinity")) {72if (na != Double.POSITIVE_INFINITY) {73fail(val, n);74}75return;76}77BigDecimal bd;78if (s.startsWith("0x")) {79s = s.substring(2);80int indP = s.indexOf('p');81long exp = Long.parseLong(s.substring(indP + 1));82int indD = s.indexOf('.');83String significand;84if (indD >= 0) {85significand = s.substring(0, indD) + s.substring(indD + 1, indP);86exp -= 4*(indP - indD - 1);87} else {88significand = s.substring(0, indP);89}90bd = new BigDecimal(new BigInteger(significand, 16));91if (exp >= 0) {92bd = bd.multiply(BigDecimal.valueOf(2).pow((int)exp));93} else {94bd = bd.divide(BigDecimal.valueOf(2).pow((int)-exp));95}96} else {97bd = new BigDecimal(s);98}99BigDecimal l, u;100if (Double.isInfinite(na)) {101l = new BigDecimal(Double.MAX_VALUE).add(new BigDecimal(Math.ulp(Double.MAX_VALUE)).multiply(HALF));102u = null;103} else {104l = new BigDecimal(na).subtract(new BigDecimal(Math.ulp(Math.nextUp(-na))).multiply(HALF));105u = new BigDecimal(na).add(new BigDecimal(Math.ulp(n)).multiply(HALF));106}107int cmpL = bd.compareTo(l);108int cmpU = u != null ? bd.compareTo(u) : -1;109if ((Double.doubleToLongBits(n) & 1) != 0) {110if (cmpL <= 0 || cmpU >= 0) {111fail(val, n);112}113} else {114if (cmpL < 0 || cmpU > 0) {115fail(val, n);116}117}118}119120private static void check(String val, double expected) {121double n = Double.parseDouble(val);122if (n != expected)123fail(val, n);124check(val);125}126127private static void rudimentaryTest() {128check(new String(""+Double.MIN_VALUE), Double.MIN_VALUE);129check(new String(""+Double.MAX_VALUE), Double.MAX_VALUE);130131check("10", (double) 10.0);132check("10.0", (double) 10.0);133check("10.01", (double) 10.01);134135check("-10", (double) -10.0);136check("-10.00", (double) -10.0);137check("-10.01", (double) -10.01);138}139140141static String badStrings[] = {142"",143"+",144"-",145"+e",146"-e",147"+e170",148"-e170",149150// Make sure intermediate white space is not deleted.151"1234 e10",152"-1234 e10",153154// Control characters in the interior of a string are not legal155"1\u0007e1",156"1e\u00071",157158// NaN and infinity can't have trailing type suffices or exponents159"NaNf",160"NaNF",161"NaNd",162"NaND",163"-NaNf",164"-NaNF",165"-NaNd",166"-NaND",167"+NaNf",168"+NaNF",169"+NaNd",170"+NaND",171"Infinityf",172"InfinityF",173"Infinityd",174"InfinityD",175"-Infinityf",176"-InfinityF",177"-Infinityd",178"-InfinityD",179"+Infinityf",180"+InfinityF",181"+Infinityd",182"+InfinityD",183184"NaNe10",185"-NaNe10",186"+NaNe10",187"Infinitye10",188"-Infinitye10",189"+Infinitye10",190191// Non-ASCII digits are not recognized192"\u0661e\u0661", // 1e1 in Arabic-Indic digits193"\u06F1e\u06F1", // 1e1 in Extended Arabic-Indic digits194"\u0967e\u0967", // 1e1 in Devanagari digits195196// JCK test lex03592m3197".",198199// JCK test lex03592m4200"e42",201202// JCK test lex03592m5203".e42",204205// JCK test lex03592m6206"d",207208// JCK test lex03592m7209".d",210211// JCK test lex03592m8212"e42d",213214// JCK test lex03592m9215".e42d",216217// JCK test lex03593m10218"1A01.01125e-10d",219220// JCK test lex03593m11221"2;3.01125e-10d",222223// JCK test lex03593m12224"1_34.01125e-10d",225226// JCK test lex03593m14227"202..01125e-10d",228229// JCK test lex03593m15230"202,01125e-10d",231232// JCK test lex03593m16233"202.03b4e-10d",234235// JCK test lex03593m18236"202.06_3e-10d",237238// JCK test lex03593m20239"202.01125e-f0d",240241// JCK test lex03593m21242"202.01125e_3d",243244// JCK test lex03593m22245"202.01125e -5d",246247// JCK test lex03593m24248"202.01125e-10r",249250// JCK test lex03593m25251"202.01125e-10ff",252253// JCK test lex03593m26254"1234L.01",255256// JCK test lex03593m27257"12ee-2",258259// JCK test lex03593m28260"12e-2.2.2",261262// JCK test lex03593m29263"12.01e+",264265// JCK test lex03593m30266"12.01E",267268// Bad hexadecimal-style strings269270// Two leading zeros271"00x1.0p1",272273// Must have hex specifier274"1.0p1",275"00010p1",276"deadbeefp1",277278// Need an explicit fully-formed exponent279"0x1.0p",280"0x1.0",281282// Exponent must be in decimal283"0x1.0pa",284"0x1.0pf",285286// Exponent separated by "p"287"0x1.0e22",288"0x1.0e22",289290// Need a signifcand291"0xp22"292};293294static String goodStrings[] = {295"NaN",296"+NaN",297"-NaN",298"Infinity",299"+Infinity",300"-Infinity",301"1.1e-23f",302".1e-23f",303"1e-23",304"1f",305"0",306"-0",307"+0",308"00",309"00",310"-00",311"+00",312"0000000000",313"-0000000000",314"+0000000000",315"1",316"2",317"1234",318"-1234",319"+1234",320"2147483647", // Integer.MAX_VALUE321"2147483648",322"-2147483648", // Integer.MIN_VALUE323"-2147483649",324325"16777215",326"16777216", // 2^24327"16777217",328329"-16777215",330"-16777216", // -2^24331"-16777217",332333"9007199254740991",334"9007199254740992", // 2^53335"9007199254740993",336337"-9007199254740991",338"-9007199254740992", // -2^53339"-9007199254740993",340341"9223372036854775807",342"9223372036854775808", // Long.MAX_VALUE343"9223372036854775809",344345"-9223372036854775808",346"-9223372036854775809", // Long.MIN_VALUE347"-9223372036854775810",348349// Culled from JCK test lex03591m1350"54.07140d",351"7.01e-324d",352"2147483647.01d",353"1.2147483647f",354"000000000000000000000000001.F",355"1.00000000000000000000000000e-2F",356357// Culled from JCK test lex03592m2358"2.",359".0909",360"122112217090.0",361"7090e-5",362"2.E-20",363".0909e42",364"122112217090.0E+100",365"7090f",366"2.F",367".0909d",368"122112217090.0D",369"7090e-5f",370"2.E-20F",371".0909e42d",372"122112217090.0E+100D",373374// Culled from JCK test lex03594m31 -- unicode escapes375"\u0035\u0031\u0034\u0039\u0032\u0033\u0036\u0037\u0038\u0030.1102E-209D",376"1290873\u002E12301e100",377"1.1E-10\u0066",378379// Culled from JCK test lex03595m1380"0.0E-10",381"1E10",382383// Culled from JCK test lex03691m1384"0.f",385"1f",386"0.F",387"1F",388"0.12d",389"1e-0d",390"12.e+1D",391"0e-0D",392"12.e+01",393"1e-01",394395// Good hex strings396// Vary capitalization of separators.397398"0x1p1",399"0X1p1",400"0x1P1",401"0X1P1",402"0x1p1f",403"0X1p1f",404"0x1P1f",405"0X1P1f",406"0x1p1F",407"0X1p1F",408"0x1P1F",409"0X1P1F",410"0x1p1d",411"0X1p1d",412"0x1P1d",413"0X1P1d",414"0x1p1D",415"0X1p1D",416"0x1P1D",417"0X1P1D",418419"-0x1p1",420"-0X1p1",421"-0x1P1",422"-0X1P1",423"-0x1p1f",424"-0X1p1f",425"-0x1P1f",426"-0X1P1f",427"-0x1p1F",428"-0X1p1F",429"-0x1P1F",430"-0X1P1F",431"-0x1p1d",432"-0X1p1d",433"-0x1P1d",434"-0X1P1d",435"-0x1p1D",436"-0X1p1D",437"-0x1P1D",438"-0X1P1D",439440"0x1p-1",441"0X1p-1",442"0x1P-1",443"0X1P-1",444"0x1p-1f",445"0X1p-1f",446"0x1P-1f",447"0X1P-1f",448"0x1p-1F",449"0X1p-1F",450"0x1P-1F",451"0X1P-1F",452"0x1p-1d",453"0X1p-1d",454"0x1P-1d",455"0X1P-1d",456"0x1p-1D",457"0X1p-1D",458"0x1P-1D",459"0X1P-1D",460461"-0x1p-1",462"-0X1p-1",463"-0x1P-1",464"-0X1P-1",465"-0x1p-1f",466"-0X1p-1f",467"-0x1P-1f",468"-0X1P-1f",469"-0x1p-1F",470"-0X1p-1F",471"-0x1P-1F",472"-0X1P-1F",473"-0x1p-1d",474"-0X1p-1d",475"-0x1P-1d",476"-0X1P-1d",477"-0x1p-1D",478"-0X1p-1D",479"-0x1P-1D",480"-0X1P-1D",481482483// Try different significand combinations484"0xap1",485"0xbp1",486"0xcp1",487"0xdp1",488"0xep1",489"0xfp1",490491"0x1p1",492"0x.1p1",493"0x1.1p1",494495"0x001p23",496"0x00.1p1",497"0x001.1p1",498499"0x100p1",500"0x.100p1",501"0x1.100p1",502503"0x00100p1",504"0x00.100p1",505"0x001.100p1",506507// Limits508509"1.7976931348623157E308", // Double.MAX_VALUE510"4.9e-324", // Double.MIN_VALUE511"2.2250738585072014e-308", // Double.MIN_NORMAL512513"2.2250738585072012e-308", // near Double.MIN_NORMAL514515"1.7976931348623158e+308", // near MAX_VALUE + ulp(MAX_VALUE)/2516"1.7976931348623159e+308", // near MAX_VALUE + ulp(MAX_VALUE)517518"2.4703282292062329e-324", // above MIN_VALUE/2519"2.4703282292062327e-324", // MIN_VALUE/2520"2.4703282292062325e-324", // below MIN_VALUE/2521522// 1e308 with leading zeros523524"0.0000000000001e321",525"00.000000000000000001e326",526"00000.000000000000000001e326",527"000.0000000000000000001e327",528"0.00000000000000000001e328",529};530531static String paddedBadStrings[];532static String paddedGoodStrings[];533static {534String pad = " \t\n\r\f\u0001\u000b\u001f";535paddedBadStrings = new String[badStrings.length];536for(int i = 0 ; i < badStrings.length; i++)537paddedBadStrings[i] = pad + badStrings[i] + pad;538539paddedGoodStrings = new String[goodStrings.length];540for(int i = 0 ; i < goodStrings.length; i++)541paddedGoodStrings[i] = pad + goodStrings[i] + pad;542543}544545546/*547* Throws an exception if <code>Input</code> is548* <code>exceptionalInput</code> and {@link Double.parseDouble549* parseDouble} does <em>not</em> throw an exception or if550* <code>Input</code> is not <code>exceptionalInput</code> and551* <code>parseDouble</code> throws an exception. This method does552* not attempt to test whether the string is converted to the553* proper value; just whether the input is accepted appropriately554* or not.555*/556private static void testParsing(String [] input,557boolean exceptionalInput) {558for(int i = 0; i < input.length; i++) {559double d;560561try {562d = Double.parseDouble(input[i]);563check(input[i]);564}565catch (NumberFormatException e) {566if (! exceptionalInput) {567throw new RuntimeException("Double.parseDouble rejected " +568"good string `" + input[i] +569"'.");570}571break;572}573if (exceptionalInput) {574throw new RuntimeException("Double.parseDouble accepted " +575"bad string `" + input[i] +576"'.");577}578}579}580581/*582* Throws an exception if <code>Input</code> is583* <code>exceptionalInput</code> and the regular expression584* matches one of the strings or if <code>Input</code> is not585* <code>exceptionalInput</code> and the regular expression fails586* to match an input string.587*/588private static void testRegex(String [] input, boolean exceptionalInput) {589/*590* The regex below is taken from the JavaDoc for591* Double.valueOf.592*/593594final String Digits = "(\\p{Digit}+)";595final String HexDigits = "(\\p{XDigit}+)";596// an exponent is 'e' or 'E' followed by an optionally597// signed decimal integer.598final String Exp = "[eE][+-]?"+Digits;599final String fpRegex =600("[\\x00-\\x20]*"+ // Optional leading "whitespace"601"[+-]?(" + // Optional sign character602"NaN|" + // "NaN" string603"Infinity|" + // "Infinity" string604605// A floating-point string representing a finite positive606// number without a leading sign has at most five basic pieces:607// Digits . Digits ExponentPart FloatTypeSuffix608//609// Since this method allows integer-only strings as input610// in addition to strings of floating-point literals, the611// two sub-patterns below are simplifications of the grammar612// productions from the Java Language Specification, 2nd613// edition, section 3.10.2.614615616// A decimal floating-point string representing a finite positive617// number without a leading sign has at most five basic pieces:618// Digits . Digits ExponentPart FloatTypeSuffix619//620// Since this method allows integer-only strings as input621// in addition to strings of floating-point literals, the622// two sub-patterns below are simplifications of the grammar623// productions from the Java Language Specification, 2nd624// edition, section 3.10.2.625626// Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt627"(((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+628629// . Digits ExponentPart_opt FloatTypeSuffix_opt630"(\\.("+Digits+")("+Exp+")?))|"+631632// Hexadecimal strings633"((" +634// 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt635"(0[xX]" + HexDigits + "(\\.)?)|" +636637// 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt638"(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +639640")[pP][+-]?" + Digits + "))" +641"[fFdD]?))" +642"[\\x00-\\x20]*");// Optional trailing "whitespace"643Pattern fpPattern = Pattern.compile(fpRegex);644645for(int i = 0; i < input.length; i++) {646Matcher m = fpPattern.matcher(input[i]);647if (m.matches() != ! exceptionalInput) {648throw new RuntimeException("Regular expression " +649(exceptionalInput?650"accepted bad":651"rejected good") +652" string `" +653input[i] + "'.");654}655}656657}658659/**660* For each subnormal power of two, test at boundaries of661* region that should convert to that value.662*/663private static void testSubnormalPowers() {664boolean failed = false;665BigDecimal TWO = BigDecimal.valueOf(2);666// An ulp is the same for all subnormal values667BigDecimal ulp_BD = new BigDecimal(Double.MIN_VALUE);668669// Test subnormal powers of two (except Double.MIN_VALUE)670for(int i = -1073; i <= -1022; i++) {671double d = Math.scalb(1.0, i);672673/*674* The region [d - ulp/2, d + ulp/2] should round to d.675*/676BigDecimal d_BD = new BigDecimal(d);677678BigDecimal lowerBound = d_BD.subtract(ulp_BD.divide(TWO));679BigDecimal upperBound = d_BD.add(ulp_BD.divide(TWO));680681double convertedLowerBound = Double.parseDouble(lowerBound.toString());682double convertedUpperBound = Double.parseDouble(upperBound.toString());683if (convertedLowerBound != d) {684failed = true;685System.out.printf("2^%d lowerBound converts as %a %s%n",686i, convertedLowerBound, lowerBound);687}688if (convertedUpperBound != d) {689failed = true;690System.out.printf("2^%d upperBound converts as %a %s%n",691i, convertedUpperBound, upperBound);692}693}694/*695* Double.MIN_VALUE696* The region ]0.5*Double.MIN_VALUE, 1.5*Double.MIN_VALUE[ should round to Double.MIN_VALUE .697*/698BigDecimal minValue = new BigDecimal(Double.MIN_VALUE);699if (Double.parseDouble(minValue.multiply(new BigDecimal(0.5)).toString()) != 0.0) {700failed = true;701System.out.printf("0.5*MIN_VALUE doesn't convert 0%n");702}703if (Double.parseDouble(minValue.multiply(new BigDecimal(0.50000000001)).toString()) != Double.MIN_VALUE) {704failed = true;705System.out.printf("0.50000000001*MIN_VALUE doesn't convert to MIN_VALUE%n");706}707if (Double.parseDouble(minValue.multiply(new BigDecimal(1.49999999999)).toString()) != Double.MIN_VALUE) {708failed = true;709System.out.printf("1.49999999999*MIN_VALUE doesn't convert to MIN_VALUE%n");710}711if (Double.parseDouble(minValue.multiply(new BigDecimal(1.5)).toString()) != 2*Double.MIN_VALUE) {712failed = true;713System.out.printf("1.5*MIN_VALUE doesn't convert to 2*MIN_VALUE%n");714}715716if (failed)717throw new RuntimeException("Inconsistent conversion");718}719720/**721* For each power of two, test at boundaries of722* region that should convert to that value.723*/724private static void testPowers() {725for(int i = -1074; i <= +1023; i++) {726double d = Math.scalb(1.0, i);727BigDecimal d_BD = new BigDecimal(d);728729BigDecimal lowerBound = d_BD.subtract(new BigDecimal(Math.ulp(Math.nextUp(-d))).multiply(HALF));730BigDecimal upperBound = d_BD.add(new BigDecimal(Math.ulp(d)).multiply(HALF));731732check(lowerBound.toString());733check(upperBound.toString());734}735check(new BigDecimal(Double.MAX_VALUE).add(new BigDecimal(Math.ulp(Double.MAX_VALUE)).multiply(HALF)).toString());736}737738private static void testStrictness() {739final double expected = 0x0.0000008000000p-1022;740// final double expected = 0x0.0000008000001p-1022;741boolean failed = false;742double conversion = 0.0;743double sum = 0.0; // Prevent conversion from being optimized away744745//2^-1047 + 2^-1075 rounds to 2^-1047746String decimal = "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316";747748for(int i = 0; i <= 12_000; i++) {749conversion = Double.parseDouble(decimal);750sum += conversion;751if (conversion != expected) {752failed = true;753System.out.printf("Iteration %d converts as %a%n",754i, conversion);755}756}757758System.out.println("Sum = " + sum);759if (failed)760throw new RuntimeException("Inconsistent conversion");761}762763public static void main(String[] args) throws Exception {764rudimentaryTest();765766testParsing(goodStrings, false);767testParsing(paddedGoodStrings, false);768testParsing(badStrings, true);769testParsing(paddedBadStrings, true);770771testRegex(goodStrings, false);772testRegex(paddedGoodStrings, false);773testRegex(badStrings, true);774testRegex(paddedBadStrings, true);775776testSubnormalPowers();777testPowers();778testStrictness();779}780}781782783