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