ceylon.language.parseFloat.ceylon Maven / Gradle / Ivy
"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."
see (`function formatFloat`,
`function parseInteger`)
tagged("Numbers", "Basic types")
shared Float? parseFloat(String string) {
// parse the sign first
Integer sign;
String unsignedPart;
if (string.startsWith("-")) {
sign = -1;
unsignedPart = string[1...];
}
else if (string.startsWith("+")) {
sign = +1;
unsignedPart = string[1...];
}
else {
sign = +1;
unsignedPart = string;
}
// split into three main parts
String wholePart;
String fractionalPart;
String? rest;
if (exists dot = unsignedPart.firstOccurrence('.')) {
wholePart = unsignedPart[...dot-1];
String afterWholePart = unsignedPart[dot+1...];
if (exists mag
= afterWholePart.firstIndexWhere(Character.letter)) {
fractionalPart = afterWholePart[...mag-1];
rest = afterWholePart[mag...];
}
else {
fractionalPart = afterWholePart;
rest = null;
}
}
else {
if (exists mag
= unsignedPart.firstIndexWhere(Character.letter)) {
wholePart = unsignedPart[...mag-1];
rest = unsignedPart[mag...];
}
else {
wholePart = unsignedPart;
rest = null;
}
fractionalPart = "0";
}
if (!wholePart.every(Character.digit) ||
!fractionalPart.every(Character.digit)) {
return null;
}
value usableWholePart
= wholePart[0:maximumIntegerExponent];
value usableFractionalPart
= fractionalPart[0:
maximumIntegerExponent
- usableWholePart.size];
value digits = usableWholePart + usableFractionalPart;
value shift
= usableFractionalPart.empty
then usableWholePart.size - wholePart.size
else usableFractionalPart.size;
Integer exponent;
if (exists rest) {
if (exists magnitude
= parseFloatExponent(rest)) {
exponent = magnitude - shift;
}
else {
return null;
}
}
else {
exponent = -shift;
}
if (exists unsigned = parseInteger(digits)) {
Float signed
= unsigned == 0
then 0 * sign.float //preserve sign of -0.0
else (sign * unsigned).nearestFloat;
value exponentMagnitude = exponent.magnitude;
if (exponentMagnitude == 0) {
return signed;
}
else if (exponentMagnitude<=maximumIntegerExponent) {
value scale = 10^exponentMagnitude;
return exponent<0
then signed / scale
else signed * scale;
}
else {
//scale can't be represented as
//an integer, resulting in some
//rounding error
return signed * 10.0^exponent;
}
}
return null;
}
//TODO: replace with a native implementation
"The maximum number of decimal digits that can be
represented by an [[Integer]]."
Integer maximumIntegerExponent
= smallest(runtime.maxIntegerValue.string.size,
runtime.minIntegerValue.string.size-1)
- 1;
Integer? parseFloatExponent(String string) {
switch (string)
case ("k") {
return 3;
}
case ("M") {
return 6;
}
case ("G") {
return 9;
}
case ("T") {
return 12;
}
case ("P") {
return 15;
}
case ("m") {
return -3;
}
case ("u") {
return -6;
}
case ("n") {
return -9;
}
case ("p") {
return -12;
}
case ("f") {
return -15;
}
else {
if (string.lowercased.startsWith("e") &&
string.rest.every(digitOrSign)) {
return parseInteger(string.rest);
}
else {
return null;
}
}
}
Boolean(Character) digitOrSign
= or(Character.digit, "+-".contains);
© 2015 - 2024 Weber Informatics LLC | Privacy Policy