1 /* 2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 4160406 4705734 4707389 6358355 7032154 27 * @summary Tests for Float.parseFloat method 28 */ 29 package test.java.lang.Float; 30 31 import java.math.BigDecimal; 32 import java.math.BigInteger; 33 34 import org.testng.annotations.Test; 35 import org.testng.Assert; 36 37 public class ParseFloatTest { 38 39 private static final BigDecimal HALF = BigDecimal.valueOf(0.5); 40 fail(String val, float n)41 private static void fail(String val, float n) { 42 Assert.fail("Float.parseFloat failed. String:" + val + " Result:" + n); 43 } 44 check(String val)45 private static void check(String val) { 46 float n = Float.parseFloat(val); 47 boolean isNegativeN = n < 0 || n == 0 && 1/n < 0; 48 float na = Math.abs(n); 49 String s = val.trim().toLowerCase(); 50 switch (s.charAt(s.length() - 1)) { 51 case 'd': 52 case 'f': 53 s = s.substring(0, s.length() - 1); 54 break; 55 } 56 boolean isNegative = false; 57 if (s.charAt(0) == '+') { 58 s = s.substring(1); 59 } else if (s.charAt(0) == '-') { 60 s = s.substring(1); 61 isNegative = true; 62 } 63 if (s.equals("nan")) { 64 if (!Float.isNaN(n)) { 65 fail(val, n); 66 } 67 return; 68 } 69 if (Float.isNaN(n)) { 70 fail(val, n); 71 } 72 if (isNegativeN != isNegative) 73 fail(val, n); 74 if (s.equals("infinity")) { 75 if (na != Float.POSITIVE_INFINITY) { 76 fail(val, n); 77 } 78 return; 79 } 80 BigDecimal bd; 81 if (s.startsWith("0x")) { 82 s = s.substring(2); 83 int indP = s.indexOf('p'); 84 long exp = Long.parseLong(s.substring(indP + 1)); 85 int indD = s.indexOf('.'); 86 String significand; 87 if (indD >= 0) { 88 significand = s.substring(0, indD) + s.substring(indD + 1, indP); 89 exp -= 4*(indP - indD - 1); 90 } else { 91 significand = s.substring(0, indP); 92 } 93 bd = new BigDecimal(new BigInteger(significand, 16)); 94 if (exp >= 0) { 95 bd = bd.multiply(BigDecimal.valueOf(2).pow((int)exp)); 96 } else { 97 bd = bd.divide(BigDecimal.valueOf(2).pow((int)-exp)); 98 } 99 } else { 100 bd = new BigDecimal(s); 101 } 102 BigDecimal l, u; 103 if (Float.isInfinite(na)) { 104 l = new BigDecimal(Float.MAX_VALUE).add(new BigDecimal(Math.ulp(Float.MAX_VALUE)).multiply(HALF)); 105 u = null; 106 } else { 107 l = new BigDecimal(na).subtract(new BigDecimal(Math.ulp(-Math.nextUp(-na))).multiply(HALF)); 108 u = new BigDecimal(na).add(new BigDecimal(Math.ulp(n)).multiply(HALF)); 109 } 110 int cmpL = bd.compareTo(l); 111 int cmpU = u != null ? bd.compareTo(u) : -1; 112 if ((Float.floatToIntBits(n) & 1) != 0) { 113 if (cmpL <= 0 || cmpU >= 0) { 114 fail(val, n); 115 } 116 } else { 117 if (cmpL < 0 || cmpU > 0) { 118 fail(val, n); 119 } 120 } 121 } 122 check(String val, float expected)123 private static void check(String val, float expected) { 124 float n = Float.parseFloat(val); 125 if (n != expected) 126 fail(val, n); 127 check(val); 128 } 129 130 @Test rudimentaryTest()131 public void rudimentaryTest() { 132 check(new String(""+Float.MIN_VALUE), Float.MIN_VALUE); 133 check(new String(""+Float.MAX_VALUE), Float.MAX_VALUE); 134 135 check("10", (float) 10.0); 136 check("10.0", (float) 10.0); 137 check("10.01", (float) 10.01); 138 139 check("-10", (float) -10.0); 140 check("-10.00", (float) -10.0); 141 check("-10.01", (float) -10.01); 142 143 // bug 6358355 144 check("144115196665790480", 0x1.000002p57f); 145 check("144115196665790481", 0x1.000002p57f); 146 check("0.050000002607703203", 0.05f); 147 check("0.050000002607703204", 0.05f); 148 check("0.050000002607703205", 0.05f); 149 check("0.050000002607703206", 0.05f); 150 check("0.050000002607703207", 0.05f); 151 check("0.050000002607703208", 0.05f); 152 check("0.050000002607703209", 0.050000004f); 153 } 154 155 static String[] badStrings = { 156 "", 157 "+", 158 "-", 159 "+e", 160 "-e", 161 "+e170", 162 "-e170", 163 164 // Make sure intermediate white space is not deleted. 165 "1234 e10", 166 "-1234 e10", 167 168 // Control characters in the interior of a string are not legal 169 "1\u0007e1", 170 "1e\u00071", 171 172 // NaN and infinity can't have trailing type suffices or exponents 173 "NaNf", 174 "NaNF", 175 "NaNd", 176 "NaND", 177 "-NaNf", 178 "-NaNF", 179 "-NaNd", 180 "-NaND", 181 "+NaNf", 182 "+NaNF", 183 "+NaNd", 184 "+NaND", 185 "Infinityf", 186 "InfinityF", 187 "Infinityd", 188 "InfinityD", 189 "-Infinityf", 190 "-InfinityF", 191 "-Infinityd", 192 "-InfinityD", 193 "+Infinityf", 194 "+InfinityF", 195 "+Infinityd", 196 "+InfinityD", 197 198 "NaNe10", 199 "-NaNe10", 200 "+NaNe10", 201 "Infinitye10", 202 "-Infinitye10", 203 "+Infinitye10", 204 205 // Non-ASCII digits are not recognized 206 "\u0661e\u0661", // 1e1 in Arabic-Indic digits 207 "\u06F1e\u06F1", // 1e1 in Extended Arabic-Indic digits 208 "\u0967e\u0967" // 1e1 in Devanagari digits 209 }; 210 211 static String[] goodStrings = { 212 "NaN", 213 "+NaN", 214 "-NaN", 215 "Infinity", 216 "+Infinity", 217 "-Infinity", 218 "1.1e-23f", 219 ".1e-23f", 220 "1e-23", 221 "1f", 222 "1", 223 "2", 224 "1234", 225 "-1234", 226 "+1234", 227 "2147483647", // Integer.MAX_VALUE 228 "2147483648", 229 "-2147483648", // Integer.MIN_VALUE 230 "-2147483649", 231 232 "16777215", 233 "16777216", // 2^24 234 "16777217", 235 236 "-16777215", 237 "-16777216", // -2^24 238 "-16777217", 239 240 "9007199254740991", 241 "9007199254740992", // 2^53 242 "9007199254740993", 243 244 "-9007199254740991", 245 "-9007199254740992", // -2^53 246 "-9007199254740993", 247 248 "9223372036854775807", 249 "9223372036854775808", // Long.MAX_VALUE 250 "9223372036854775809", 251 252 "-9223372036854775808", 253 "-9223372036854775809", // Long.MIN_VALUE 254 "-9223372036854775810" 255 }; 256 257 static String[] paddedBadStrings; 258 static String[] paddedGoodStrings; 259 static { 260 String pad = " \t\n\r\f\u0001\u000b\u001f"; 261 paddedBadStrings = new String[badStrings.length]; 262 for(int i = 0 ; i < badStrings.length; i++) 263 paddedBadStrings[i] = pad + badStrings[i] + pad; 264 265 paddedGoodStrings = new String[goodStrings.length]; 266 for(int i = 0 ; i < goodStrings.length; i++) 267 paddedGoodStrings[i] = pad + goodStrings[i] + pad; 268 269 } 270 271 /* 272 * Throws an exception if <code>Input</code> is 273 * <code>exceptionalInput</code> and {@link Float.parseFloat 274 * parseFloat} does <em>not</em> throw an exception or if 275 * <code>Input</code> is not <code>exceptionalInput</code> and 276 * <code>parseFloat</code> throws an exception. This method does 277 * not attempt to test whether the string is converted to the 278 * proper value; just whether the input is accepted appropriately 279 * or not. 280 */ testParsing(String [] input, boolean exceptionalInput)281 private static void testParsing(String [] input, 282 boolean exceptionalInput) { 283 for(int i = 0; i < input.length; i++) { 284 double d; 285 286 try { 287 d = Float.parseFloat(input[i]); 288 check(input[i]); 289 } 290 catch (NumberFormatException e) { 291 if (! exceptionalInput) { 292 throw new RuntimeException("Float.parseFloat rejected " + 293 "good string `" + input[i] + 294 "'."); 295 } 296 break; 297 } 298 if (exceptionalInput) { 299 throw new RuntimeException("Float.parseFloat accepted " + 300 "bad string `" + input[i] + 301 "'."); 302 } 303 } 304 } 305 306 /** 307 * For each power of two, test at boundaries of 308 * region that should convert to that value. 309 */ 310 @Test testPowers()311 public void testPowers() { 312 for(int i = -149; i <= +127; i++) { 313 float f = Math.scalb(1.0f, i); 314 BigDecimal f_BD = new BigDecimal(f); 315 316 BigDecimal lowerBound = f_BD.subtract(new BigDecimal(Math.ulp(-Math.nextUp(-f))).multiply(HALF)); 317 BigDecimal upperBound = f_BD.add(new BigDecimal(Math.ulp(f)).multiply(HALF)); 318 319 check(lowerBound.toString()); 320 check(upperBound.toString()); 321 } 322 check(new BigDecimal(Float.MAX_VALUE).add(new BigDecimal(Math.ulp(Float.MAX_VALUE)).multiply(HALF)).toString()); 323 } 324 325 @Test testParsing()326 public void testParsing() { 327 testParsing(goodStrings, false); 328 testParsing(paddedGoodStrings, false); 329 testParsing(badStrings, true); 330 testParsing(paddedBadStrings, true); 331 } 332 } 333