strconv: cleanup atof.c.v - use a ParserState enum, clarify comments
parent
e4dfffd70b
commit
843ce43077
|
@ -1,26 +1,47 @@
|
|||
module strconv
|
||||
|
||||
/*
|
||||
atof util
|
||||
// Copyright (c) 2019-2022 Dario Deledda. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
//
|
||||
// This file contains utilities for converting a string to a f64 variable.
|
||||
// IEEE 754 standard is used.
|
||||
// Know limitation: limited to 18 significant digits
|
||||
//
|
||||
// The code is inspired by:
|
||||
// Grzegorz Kraszewski krashan@teleinfo.pb.edu.pl
|
||||
// URL: http://krashan.ppa.pl/articles/stringtofloat/
|
||||
// Original license: MIT
|
||||
// 96 bit operation utilities
|
||||
//
|
||||
// Note: when u128 will be available, these function can be refactored.
|
||||
|
||||
Copyright (c) 2019-2022 Dario Deledda. All rights reserved.
|
||||
Use of this source code is governed by an MIT license
|
||||
that can be found in the LICENSE file.
|
||||
// f32 constants
|
||||
pub const (
|
||||
single_plus_zero = u32(0x0000_0000)
|
||||
single_minus_zero = u32(0x8000_0000)
|
||||
single_plus_infinity = u32(0x7F80_0000)
|
||||
single_minus_infinity = u32(0xFF80_0000)
|
||||
)
|
||||
|
||||
This file contains utilities for convert a string in a f64 variable
|
||||
IEEE 754 standard is used
|
||||
// f64 constants
|
||||
pub const (
|
||||
digits = 18
|
||||
double_plus_zero = u64(0x0000000000000000)
|
||||
double_minus_zero = u64(0x8000000000000000)
|
||||
double_plus_infinity = u64(0x7FF0000000000000)
|
||||
double_minus_infinity = u64(0xFFF0000000000000)
|
||||
)
|
||||
|
||||
Know limitation:
|
||||
- limited to 18 significant digits
|
||||
|
||||
The code is inspired by:
|
||||
Grzegorz Kraszewski krashan@teleinfo.pb.edu.pl
|
||||
URL: http://krashan.ppa.pl/articles/stringtofloat/
|
||||
Original license: MIT
|
||||
|
||||
96 bit operation utilities
|
||||
Note: when u128 will be available these function can be refactored
|
||||
*/
|
||||
// char constants
|
||||
pub const (
|
||||
c_dpoint = `.`
|
||||
c_plus = `+`
|
||||
c_minus = `-`
|
||||
c_zero = `0`
|
||||
c_nine = `9`
|
||||
c_ten = u32(10)
|
||||
)
|
||||
|
||||
// right logical shift 96 bit
|
||||
fn lsr96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) {
|
||||
|
@ -78,48 +99,7 @@ fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) {
|
|||
return r2, r1, r0
|
||||
}
|
||||
|
||||
// Constants
|
||||
|
||||
pub const (
|
||||
//
|
||||
// f32 constants
|
||||
//
|
||||
single_plus_zero = u32(0x0000_0000)
|
||||
single_minus_zero = u32(0x8000_0000)
|
||||
single_plus_infinity = u32(0x7F80_0000)
|
||||
single_minus_infinity = u32(0xFF80_0000)
|
||||
//
|
||||
// f64 constants
|
||||
//
|
||||
digits = 18
|
||||
double_plus_zero = u64(0x0000000000000000)
|
||||
double_minus_zero = u64(0x8000000000000000)
|
||||
double_plus_infinity = u64(0x7FF0000000000000)
|
||||
double_minus_infinity = u64(0xFFF0000000000000)
|
||||
//
|
||||
// Possible parser return values.
|
||||
//
|
||||
parser_ok = 0 // parser finished OK
|
||||
parser_pzero = 1 // no digits or number is smaller than +-2^-1022
|
||||
parser_mzero = 2 // number is negative, module smaller
|
||||
parser_pinf = 3 // number is higher than +HUGE_VAL
|
||||
parser_minf = 4 // number is lower than -HUGE_VAL
|
||||
parser_invalid_number = 5 // invalid number, used for '#@%^' for example
|
||||
//
|
||||
// char constants
|
||||
// Note: Modify these if working with non-ASCII encoding
|
||||
//
|
||||
c_dpoint = `.`
|
||||
c_plus = `+`
|
||||
c_minus = `-`
|
||||
c_zero = `0`
|
||||
c_nine = `9`
|
||||
c_ten = u32(10)
|
||||
)
|
||||
|
||||
// Utility functions
|
||||
|
||||
// NOTE: Modify these if working with non-ASCII encoding
|
||||
fn is_digit(x byte) bool {
|
||||
return (x >= strconv.c_zero && x <= strconv.c_nine) == true
|
||||
}
|
||||
|
@ -132,14 +112,21 @@ fn is_exp(x byte) bool {
|
|||
return (x == `E` || x == `e`) == true
|
||||
}
|
||||
|
||||
/*
|
||||
String parser
|
||||
NOTE: #TOFIX need one char after the last char of the number
|
||||
*/
|
||||
// Possible parser return values.
|
||||
enum ParserState {
|
||||
ok // parser finished OK
|
||||
pzero // no digits or number is smaller than +-2^-1022
|
||||
mzero // number is negative, module smaller
|
||||
pinf // number is higher than +HUGE_VAL
|
||||
minf // number is lower than -HUGE_VAL
|
||||
invalid_number // invalid number, used for '#@%^' for example
|
||||
}
|
||||
|
||||
fn parser(s string) (int, PrepNumber) {
|
||||
// parser tries to parse the given string into a number
|
||||
// NOTE: #TOFIX need one char after the last char of the number
|
||||
fn parser(s string) (ParserState, PrepNumber) {
|
||||
mut digx := 0
|
||||
mut result := strconv.parser_ok
|
||||
mut result := ParserState.ok
|
||||
mut expneg := false
|
||||
mut expexp := 0
|
||||
mut i := 0
|
||||
|
@ -216,45 +203,45 @@ fn parser(s string) (int, PrepNumber) {
|
|||
pn.exponent += expexp
|
||||
if pn.mantissa == 0 {
|
||||
if pn.negative {
|
||||
result = strconv.parser_mzero
|
||||
result = .mzero
|
||||
} else {
|
||||
result = strconv.parser_pzero
|
||||
result = .pzero
|
||||
}
|
||||
} else if pn.exponent > 309 {
|
||||
if pn.negative {
|
||||
result = strconv.parser_minf
|
||||
result = .minf
|
||||
} else {
|
||||
result = strconv.parser_pinf
|
||||
result = .pinf
|
||||
}
|
||||
} else if pn.exponent < -328 {
|
||||
if pn.negative {
|
||||
result = strconv.parser_mzero
|
||||
result = .mzero
|
||||
} else {
|
||||
result = strconv.parser_pzero
|
||||
result = .pzero
|
||||
}
|
||||
}
|
||||
if i == 0 && s.len > 0 {
|
||||
return strconv.parser_invalid_number, pn
|
||||
return ParserState.invalid_number, pn
|
||||
}
|
||||
return result, pn
|
||||
}
|
||||
|
||||
/*
|
||||
Converter to the bit form of the f64 number
|
||||
*/
|
||||
|
||||
// converter return a u64 with the bit image of the f64 number
|
||||
// converter returns a u64 with the bit image of the f64 number
|
||||
fn converter(mut pn PrepNumber) u64 {
|
||||
mut binexp := 92
|
||||
mut s2 := u32(0) // 96-bit precision integer
|
||||
// s0,s1,s2 are the parts of a 96-bit precision integer
|
||||
mut s2 := u32(0)
|
||||
mut s1 := u32(0)
|
||||
mut s0 := u32(0)
|
||||
mut q2 := u32(0) // 96-bit precision integer
|
||||
// q0,q1,q2 are the parts of a 96-bit precision integer
|
||||
mut q2 := u32(0)
|
||||
mut q1 := u32(0)
|
||||
mut q0 := u32(0)
|
||||
mut r2 := u32(0) // 96-bit precision integer
|
||||
// r0,r1,r2 are the parts of a 96-bit precision integer
|
||||
mut r2 := u32(0)
|
||||
mut r1 := u32(0)
|
||||
mut r0 := u32(0)
|
||||
//
|
||||
mask28 := u32(u64(0xF) << 28)
|
||||
mut result := u64(0)
|
||||
// working on 3 u32 to have 96 bit precision
|
||||
|
@ -404,35 +391,30 @@ fn converter(mut pn PrepNumber) u64 {
|
|||
return result
|
||||
}
|
||||
|
||||
// Public functions
|
||||
|
||||
// atof64 return a f64 from a string doing a parsing operation
|
||||
// atof64 parses the string `s`, and if possible, converts it into a f64 number
|
||||
pub fn atof64(s string) ?f64 {
|
||||
if s.len == 0 {
|
||||
return error('expected a number found an empty string')
|
||||
}
|
||||
mut pn := PrepNumber{}
|
||||
mut res_parsing := 0
|
||||
mut res := Float64u{}
|
||||
|
||||
res_parsing, pn = parser(s)
|
||||
mut res_parsing, mut pn := parser(s)
|
||||
match res_parsing {
|
||||
strconv.parser_ok {
|
||||
.ok {
|
||||
res.u = converter(mut pn)
|
||||
}
|
||||
strconv.parser_pzero {
|
||||
.pzero {
|
||||
res.u = strconv.double_plus_zero
|
||||
}
|
||||
strconv.parser_mzero {
|
||||
.mzero {
|
||||
res.u = strconv.double_minus_zero
|
||||
}
|
||||
strconv.parser_pinf {
|
||||
.pinf {
|
||||
res.u = strconv.double_plus_infinity
|
||||
}
|
||||
strconv.parser_minf {
|
||||
.minf {
|
||||
res.u = strconv.double_minus_infinity
|
||||
}
|
||||
else {
|
||||
.invalid_number {
|
||||
return error('not a number')
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue