aboutsummaryrefslogtreecommitdiff
path: root/core/strconv
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2023-03-06 12:39:52 +0000
committergingerBill <bill@gingerbill.org>2023-03-06 12:39:52 +0000
commitff275df5ea01d24960c60d43a14db274db4eefd8 (patch)
tree8cd090c65f9130f1155795c48033b3d260991ef0 /core/strconv
parent6e56e5457d921a6f3fea8736b6c237fa5952825b (diff)
Fix parsing C-like hex floats
Diffstat (limited to 'core/strconv')
-rw-r--r--core/strconv/strconv.odin50
1 files 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