```"The [[Float]] value of the given
[[string representation|string]] of a decimal floating
point number, or `null` if the string does not represent a
decimal floating point number.

If the given string representation contains more digits
than can be represented by a `Float`, then the least
significant digits are ignored.

The syntax accepted by this method is the same as the
syntax for a `Float` literal in the Ceylon language
except that it may optionally begin with a sign
character (`+` or `-`) and may not contain grouping
underscore characters. That is, an optional sign character,
followed by a string of decimal digits, followed by an
optional decimal point and string of decimal digits,
followed by an optional decimal exponent, for example
`e+10` or `E-5`, or SI magnitude, `k`, `M`, `G`, `T`, `P`,
`m`, `u`, `n`, `p`, or `f`.

Float: Sign? Digits ('.' Digits)? (Magnitude|Exponent)
Sign: '+' | '-'
Magnitude: 'k' | 'M' | 'G' | 'T' | 'P' | 'm' | 'u' | 'n' | 'p' | 'f'
Exponent: ('e'|'E') Sign? Digits
Digits: ('0'..'9')+"
see (`function Float.parse`)
tagged("Numbers", "Basic types")
deprecated("Use [[Float.parse]]")
shared Float? parseFloat(String string)
=> if (is Float result
= parseFloatInternal(string))
then result
else null;

class ParseFloatState
of start
| afterPlusMinus
| digitsBeforeDecimal
| afterJustDecimal
| afterDecimal
| digitsAfterDecimal
| afterE
| exponentDigits
| afterEPlusMinus
| afterSuffix
| invalid {

shared new start {}
shared new afterPlusMinus {}
shared new digitsBeforeDecimal {}
shared new afterJustDecimal {}
shared new afterDecimal {}
shared new digitsAfterDecimal {}
shared new afterE {}
shared new exponentDigits {}
shared new afterEPlusMinus {}
shared new afterSuffix {}
shared new invalid {}
}

Float|ParseException parseFloatInternal(String string) {

import ceylon.language {
ParseFloatState {
start, afterPlusMinus, digitsBeforeDecimal,
afterJustDecimal, afterDecimal, digitsAfterDecimal,
afterE, exponentDigits, afterEPlusMinus,
afterSuffix, invalid
}
}

// ("-"|"+")?
// (Digit* "." Digit+) | (Digit+ "."?)
// (("E"|"e") ("+"|"-")? Digit+) | suffix

variable value state = start;
variable value size = 0;
variable Integer? suffixExponent = null;

for (ch in string) {
size++;
state = switch (state)
case (start)
if (ch == '+' || ch == '-')
then afterPlusMinus
else if ('0' <= ch <= '9')
then digitsBeforeDecimal
else if (ch == '.')
then afterJustDecimal
else invalid
case (afterPlusMinus)
if ('0' <= ch <= '9')
then digitsBeforeDecimal
else if (ch == '.')
then afterJustDecimal
else invalid
case (digitsBeforeDecimal)
if ('0' <= ch <= '9')
then digitsBeforeDecimal
else if (ch == '.')
then afterDecimal
else if (ch == 'e' || ch == 'E')
then afterE
else if (ch in "PTGMkmunpf")
then afterSuffix
else invalid
case (afterJustDecimal)
if ('0' <= ch <= '9')
then digitsAfterDecimal
else invalid
case (digitsAfterDecimal |
afterDecimal)
if ('0' <= ch <= '9')
then digitsAfterDecimal
else if (ch == 'e' || ch == 'E')
then afterE
else if (ch in "PTGMkmunpf")
then afterSuffix
else invalid
case (afterE)
if ('0' <= ch <= '9')
then exponentDigits
else if (ch == '+' || ch == '-')
then afterEPlusMinus
else invalid
case (exponentDigits |
afterEPlusMinus)
if ('0' <= ch <= '9')
then exponentDigits
else invalid
case (afterSuffix)
invalid
case (invalid)
invalid;

if (state == afterSuffix) {
suffixExponent = parseSuffix(ch);
}

if (state == invalid) {
return ParseException("illegal format for Float: unexpected character '``ch``'");
}
}

if (!state in [digitsBeforeDecimal,
afterDecimal, digitsAfterDecimal,
exponentDigits, afterSuffix]) {
return ParseException("illegal format for Float: unexpected end of string");
}

try {
if (exists exponent = suffixExponent) {
// Ceylon style magnitude suffix
return nativeParseFloat(string[0:size-1] + "E" + exponent.string);
}
else {
// may or may not have exponent
return nativeParseFloat(string);
}
}
catch (e) {
return ParseException("illegal format for Float: " + e.message);
}
}

Integer parseSuffix(Character suffix) {
switch (suffix)
case ('P') {
return 15;
}
case ('T') {
return 12;
}
case ('G') {
return 9;
}
case ('M') {
return 6;
}
case ('k') {
return 3;
}
case ('m') {
return -3;
}
case ('u') {
return -6;
}
case ('n') {
return -9;
}
case ('p') {
return -12;
}
case ('f') {
return -15;
}
else {
"unrecognized SI magnitude"
assert (false);
}
}

native
Float nativeParseFloat(String string);

native("jvm")
Float nativeParseFloat(String string) {
import java.lang {
Double {
parseDouble
}
}

return parseDouble(string);
}

native("js")
Float nativeParseFloat(String string) {
Float result;
dynamic {
result = nativeJSParseFloat(string);
}
if (result == 0.0 && string.occursAt(0, '-')) {
return -0.0;
}
return result;
}
```