mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
strconv: cleanup atof.c.v - use a ParserState enum, clarify comments
This commit is contained in:
parent
e4dfffd70b
commit
843ce43077
@ -1,26 +1,47 @@
|
|||||||
module strconv
|
module strconv
|
||||||
|
|
||||||
/*
|
// Copyright (c) 2019-2022 Dario Deledda. All rights reserved.
|
||||||
atof util
|
// 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.
|
// f32 constants
|
||||||
Use of this source code is governed by an MIT license
|
pub const (
|
||||||
that can be found in the LICENSE file.
|
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
|
// f64 constants
|
||||||
IEEE 754 standard is used
|
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:
|
// char constants
|
||||||
- limited to 18 significant digits
|
pub const (
|
||||||
|
c_dpoint = `.`
|
||||||
The code is inspired by:
|
c_plus = `+`
|
||||||
Grzegorz Kraszewski krashan@teleinfo.pb.edu.pl
|
c_minus = `-`
|
||||||
URL: http://krashan.ppa.pl/articles/stringtofloat/
|
c_zero = `0`
|
||||||
Original license: MIT
|
c_nine = `9`
|
||||||
|
c_ten = u32(10)
|
||||||
96 bit operation utilities
|
)
|
||||||
Note: when u128 will be available these function can be refactored
|
|
||||||
*/
|
|
||||||
|
|
||||||
// right logical shift 96 bit
|
// right logical shift 96 bit
|
||||||
fn lsr96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) {
|
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
|
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
|
// Utility functions
|
||||||
|
|
||||||
// NOTE: Modify these if working with non-ASCII encoding
|
|
||||||
fn is_digit(x byte) bool {
|
fn is_digit(x byte) bool {
|
||||||
return (x >= strconv.c_zero && x <= strconv.c_nine) == true
|
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
|
return (x == `E` || x == `e`) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Possible parser return values.
|
||||||
String parser
|
enum ParserState {
|
||||||
NOTE: #TOFIX need one char after the last char of the number
|
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 digx := 0
|
||||||
mut result := strconv.parser_ok
|
mut result := ParserState.ok
|
||||||
mut expneg := false
|
mut expneg := false
|
||||||
mut expexp := 0
|
mut expexp := 0
|
||||||
mut i := 0
|
mut i := 0
|
||||||
@ -216,45 +203,45 @@ fn parser(s string) (int, PrepNumber) {
|
|||||||
pn.exponent += expexp
|
pn.exponent += expexp
|
||||||
if pn.mantissa == 0 {
|
if pn.mantissa == 0 {
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
result = strconv.parser_mzero
|
result = .mzero
|
||||||
} else {
|
} else {
|
||||||
result = strconv.parser_pzero
|
result = .pzero
|
||||||
}
|
}
|
||||||
} else if pn.exponent > 309 {
|
} else if pn.exponent > 309 {
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
result = strconv.parser_minf
|
result = .minf
|
||||||
} else {
|
} else {
|
||||||
result = strconv.parser_pinf
|
result = .pinf
|
||||||
}
|
}
|
||||||
} else if pn.exponent < -328 {
|
} else if pn.exponent < -328 {
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
result = strconv.parser_mzero
|
result = .mzero
|
||||||
} else {
|
} else {
|
||||||
result = strconv.parser_pzero
|
result = .pzero
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if i == 0 && s.len > 0 {
|
if i == 0 && s.len > 0 {
|
||||||
return strconv.parser_invalid_number, pn
|
return ParserState.invalid_number, pn
|
||||||
}
|
}
|
||||||
return result, pn
|
return result, pn
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// converter returns a u64 with the bit image of the f64 number
|
||||||
Converter to the bit form of the f64 number
|
|
||||||
*/
|
|
||||||
|
|
||||||
// converter return a u64 with the bit image of the f64 number
|
|
||||||
fn converter(mut pn PrepNumber) u64 {
|
fn converter(mut pn PrepNumber) u64 {
|
||||||
mut binexp := 92
|
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 s1 := u32(0)
|
||||||
mut s0 := 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 q1 := u32(0)
|
||||||
mut q0 := 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 r1 := u32(0)
|
||||||
mut r0 := u32(0)
|
mut r0 := u32(0)
|
||||||
|
//
|
||||||
mask28 := u32(u64(0xF) << 28)
|
mask28 := u32(u64(0xF) << 28)
|
||||||
mut result := u64(0)
|
mut result := u64(0)
|
||||||
// working on 3 u32 to have 96 bit precision
|
// working on 3 u32 to have 96 bit precision
|
||||||
@ -404,35 +391,30 @@ fn converter(mut pn PrepNumber) u64 {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public functions
|
// atof64 parses the string `s`, and if possible, converts it into a f64 number
|
||||||
|
|
||||||
// atof64 return a f64 from a string doing a parsing operation
|
|
||||||
pub fn atof64(s string) ?f64 {
|
pub fn atof64(s string) ?f64 {
|
||||||
if s.len == 0 {
|
if s.len == 0 {
|
||||||
return error('expected a number found an empty string')
|
return error('expected a number found an empty string')
|
||||||
}
|
}
|
||||||
mut pn := PrepNumber{}
|
|
||||||
mut res_parsing := 0
|
|
||||||
mut res := Float64u{}
|
mut res := Float64u{}
|
||||||
|
mut res_parsing, mut pn := parser(s)
|
||||||
res_parsing, pn = parser(s)
|
|
||||||
match res_parsing {
|
match res_parsing {
|
||||||
strconv.parser_ok {
|
.ok {
|
||||||
res.u = converter(mut pn)
|
res.u = converter(mut pn)
|
||||||
}
|
}
|
||||||
strconv.parser_pzero {
|
.pzero {
|
||||||
res.u = strconv.double_plus_zero
|
res.u = strconv.double_plus_zero
|
||||||
}
|
}
|
||||||
strconv.parser_mzero {
|
.mzero {
|
||||||
res.u = strconv.double_minus_zero
|
res.u = strconv.double_minus_zero
|
||||||
}
|
}
|
||||||
strconv.parser_pinf {
|
.pinf {
|
||||||
res.u = strconv.double_plus_infinity
|
res.u = strconv.double_plus_infinity
|
||||||
}
|
}
|
||||||
strconv.parser_minf {
|
.minf {
|
||||||
res.u = strconv.double_minus_infinity
|
res.u = strconv.double_minus_infinity
|
||||||
}
|
}
|
||||||
else {
|
.invalid_number {
|
||||||
return error('not a number')
|
return error('not a number')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user