Skip to content
Snippets Groups Projects
Commit ec1fb94f authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Merge branch 'functions/strto_float/nan_inf' into 'master'

strtof(), strtod(): handle NaN and Infinity

See merge request redox-os/relibc!405
parents fe02a5bd b66df46f
No related branches found
No related tags found
No related merge requests found
...@@ -227,19 +227,19 @@ macro_rules! strto_impl { ...@@ -227,19 +227,19 @@ macro_rules! strto_impl {
num num
}}; }};
} }
#[macro_export] #[macro_export]
macro_rules! strto_float_impl { macro_rules! strto_float_impl {
($type:ident, $s:expr, $endptr:expr) => {{ ($type:ident, $s:expr, $endptr:expr) => {{
let mut s = $s; let mut s = $s;
let endptr = $endptr; let endptr = $endptr;
// TODO: Handle named floats: NaN, Inf...
while ctype::isspace(*s as c_int) != 0 { while ctype::isspace(*s as c_int) != 0 {
s = s.offset(1); s = s.offset(1);
} }
let mut result: $type = 0.0; let mut result: $type = 0.0;
let mut exponent: Option<$type> = None;
let mut radix = 10; let mut radix = 10;
let result_sign = match *s as u8 { let result_sign = match *s as u8 {
...@@ -254,75 +254,88 @@ macro_rules! strto_float_impl { ...@@ -254,75 +254,88 @@ macro_rules! strto_float_impl {
_ => 1.0, _ => 1.0,
}; };
if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' { let rust_s = CStr::from_ptr(s).to_string_lossy();
s = s.offset(2);
radix = 16; // detect NaN, Inf
} if rust_s.to_lowercase().starts_with("inf") {
result = $type::INFINITY;
while let Some(digit) = (*s as u8 as char).to_digit(radix) { s = s.offset(3);
result *= radix as $type; } else if rust_s.to_lowercase().starts_with("nan") {
result += digit as $type; // we cannot signal negative NaN in LLVM backed languages
s = s.offset(1); // https://github.com/rust-lang/rust/issues/73328 , https://github.com/rust-lang/rust/issues/81261
} result = $type::NAN;
s = s.offset(3);
if *s as u8 == b'.' { } else {
s = s.offset(1); if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' {
s = s.offset(2);
radix = 16;
}
let mut i = 1.0;
while let Some(digit) = (*s as u8 as char).to_digit(radix) { while let Some(digit) = (*s as u8 as char).to_digit(radix) {
i *= radix as $type; result *= radix as $type;
result += digit as $type / i; result += digit as $type;
s = s.offset(1); s = s.offset(1);
} }
}
let s_before_exponent = s;
let exponent = match (*s as u8, radix) { if *s as u8 == b'.' {
(b'e' | b'E', 10) | (b'p' | b'P', 16) => {
s = s.offset(1); s = s.offset(1);
let is_exponent_positive = match *s as u8 { let mut i = 1.0;
b'-' => { while let Some(digit) = (*s as u8 as char).to_digit(radix) {
s = s.offset(1); i *= radix as $type;
false result += digit as $type / i;
} s = s.offset(1);
b'+' => { }
s = s.offset(1); }
true
}
_ => true,
};
// Exponent digits are always in base 10.
if (*s as u8 as char).is_digit(10) {
let mut exponent_value = 0;
while let Some(digit) = (*s as u8 as char).to_digit(10) {
exponent_value *= 10;
exponent_value += digit;
s = s.offset(1);
}
let exponent_base = match radix { let s_before_exponent = s;
10 => 10u128,
16 => 2u128, exponent = match (*s as u8, radix) {
_ => unreachable!(), (b'e' | b'E', 10) | (b'p' | b'P', 16) => {
s = s.offset(1);
let is_exponent_positive = match *s as u8 {
b'-' => {
s = s.offset(1);
false
}
b'+' => {
s = s.offset(1);
true
}
_ => true,
}; };
if is_exponent_positive { // Exponent digits are always in base 10.
Some(exponent_base.pow(exponent_value) as $type) if (*s as u8 as char).is_digit(10) {
let mut exponent_value = 0;
while let Some(digit) = (*s as u8 as char).to_digit(10) {
exponent_value *= 10;
exponent_value += digit;
s = s.offset(1);
}
let exponent_base = match radix {
10 => 10u128,
16 => 2u128,
_ => unreachable!(),
};
if is_exponent_positive {
Some(exponent_base.pow(exponent_value) as $type)
} else {
Some(1.0 / (exponent_base.pow(exponent_value) as $type))
}
} else { } else {
Some(1.0 / (exponent_base.pow(exponent_value) as $type)) // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback
s = s_before_exponent;
None
} }
} else {
// Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback
s = s_before_exponent;
None
} }
} _ => None,
_ => None, };
}; }
if !endptr.is_null() { if !endptr.is_null() {
// This is stupid, but apparently strto* functions want // This is stupid, but apparently strto* functions want
......
-3.140000 -3.140000
inf
...@@ -169,3 +169,28 @@ d: -49999999999999998431683053958987776.000000 Endptr: "" ...@@ -169,3 +169,28 @@ d: -49999999999999998431683053958987776.000000 Endptr: ""
d: -500000000000000021210318687008980992.000000 Endptr: "" d: -500000000000000021210318687008980992.000000 Endptr: ""
d: -4999999999999999769381329101060571136.000000 Endptr: "" d: -4999999999999999769381329101060571136.000000 Endptr: ""
d: -49999999999999998874404911728017014784.000000 Endptr: "" d: -49999999999999998874404911728017014784.000000 Endptr: ""
d: -0.000000 Endptr: ""
d: inf Endptr: ""
d: inf Endptr: ""
d: inf Endptr: ""
d: inf Endptr: " foobarbaz"
d: inf Endptr: ""
d: inf Endptr: ""
d: inf Endptr: ""
d: inf Endptr: " foobarbaz"
d: -inf Endptr: ""
d: -inf Endptr: ""
d: -inf Endptr: ""
d: -inf Endptr: " foobarbaz"
d: nan Endptr: "0.1e5"
d: nan Endptr: "-37"
d: nan Endptr: "1.05"
d: nan Endptr: " foo bar baz"
d: nan Endptr: "0.1e5"
d: nan Endptr: "-37"
d: nan Endptr: "1.05"
d: nan Endptr: " foo bar baz"
d: nan Endptr: "0.1e5"
d: nan Endptr: "-37"
d: nan Endptr: "1.05"
d: nan Endptr: " foo bar baz"
...@@ -6,4 +6,7 @@ ...@@ -6,4 +6,7 @@
int main(void) { int main(void) {
double d = atof("-3.14"); double d = atof("-3.14");
printf("%f\n", d); printf("%f\n", d);
d = atof("INF");
printf("%f\n", d);
} }
...@@ -61,6 +61,17 @@ int main(void) { ...@@ -61,6 +61,17 @@ int main(void) {
"-0.5e25", "-0.5e26", "-0.5e27", "-0.5e28", "-0.5e29", "-0.5e25", "-0.5e26", "-0.5e27", "-0.5e28", "-0.5e29",
"-0.5e30", "-0.5e31", "-0.5e32", "-0.5e33", "-0.5e34", "-0.5e30", "-0.5e31", "-0.5e32", "-0.5e33", "-0.5e34",
"-0.5e35", "-0.5e36", "-0.5e37", "-0.5e38", "-0.5e35", "-0.5e36", "-0.5e37", "-0.5e38",
"-0",
"INF", "inf", "iNf", "Inf foobarbaz",
"+INF", "+inf", "+iNf", "+Inf foobarbaz",
"-INF", "-inf", "-iNf", "-Inf foobarbaz",
"NaN0.1e5", "nan-37", "nAn1.05", "Nan foo bar baz",
"+NaN0.1e5", "+nan-37", "+nAn1.05", "+Nan foo bar baz",
"-NaN0.1e5", "-nan-37", "-nAn1.05", "-Nan foo bar baz",
}; };
for (int i = 0; i < sizeof(inputs) / sizeof(char*); i += 1) { for (int i = 0; i < sizeof(inputs) / sizeof(char*); i += 1) {
d = strtod(inputs[i], &endptr); d = strtod(inputs[i], &endptr);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment