From ff275df5ea01d24960c60d43a14db274db4eefd8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 6 Mar 2023 12:39:52 +0000 Subject: [PATCH] Fix parsing C-like hex floats --- core/strconv/strconv.odin | 50 ++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 6d7374760..816322aee 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -556,19 +556,49 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) { return f32(v), ok } + +parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { + value, n^, ok = parse_f64_prefix(str) + if ok && len(str) != n^ { + ok = false + } + return +} + + +// Parses a 32-bit floating point number from a string. +// +// Returns ok=false if a base 10 float could not be found, +// or if the input string contained more than just the number. +// +// ``` +// n, _, ok := strconv.parse_f32("12.34eee"); +// assert(n == 12.34 && ok); +// +// n, _, ok = strconv.parse_f32("12.34"); +// assert(n == 12.34 && ok); +// ``` +parse_f32_prefix :: proc(str: string) -> (value: f32, nr: int, ok: bool) { + f: f64 + f, nr, ok = parse_f64_prefix(str) + value = f32(f) + return +} + + // Parses a 64-bit floating point number from a string. // // Returns ok=false if a base 10 float could not be found, // or if the input string contained more than just the number. // // ``` -// n, ok := strconv.parse_f32("12.34eee"); +// n, _, ok := strconv.parse_f32("12.34eee"); // assert(n == 12.34 && ok); // -// n, ok = strconv.parse_f32("12.34"); +// n, _, ok = strconv.parse_f32("12.34"); // assert(n == 12.34 && ok); // ``` -parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { +parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) { common_prefix_len_ignore_case :: proc "contextless" (s, prefix: string) -> int { n := len(prefix) if n > len(s) { @@ -751,7 +781,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { mantissa |= 1 } - for mantissa >> (info.mantbits+2) == 0 { + for mantissa != 0 && mantissa >> (info.mantbits+2) == 0 { mantissa = mantissa>>1 | mantissa&1 exp += 1 } @@ -795,9 +825,6 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { } - nr: int - defer if n != nil { n^ = nr } - if value, nr, ok = check_special(str); ok { return } @@ -808,7 +835,8 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { mantissa, exp, neg, trunc, hex, nr = parse_components(str) or_return if hex { - return parse_hex(str, mantissa, exp, neg, trunc) + value, ok = parse_hex(str, mantissa, exp, neg, trunc) + return } trunc_block: if !trunc { @@ -827,7 +855,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { } switch { case exp == 0: - return f, true + return f, nr, true case exp > 0 && exp <= 15+22: if exp > 22 { f *= pow10[exp-22] @@ -836,9 +864,9 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { if f > 1e15 || f < 1e-15 { break trunc_block } - return f * pow10[exp], true + return f * pow10[exp], nr, true case -22 <= exp && exp < 0: - return f / pow10[-exp], true + return f / pow10[-exp], nr, true } } d: decimal.Decimal