diff --git a/vlib/strconv/atof.c.v b/vlib/strconv/atof.c.v index e60f4a1e2f..11663976e3 100644 --- a/vlib/strconv/atof.c.v +++ b/vlib/strconv/atof.c.v @@ -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') } }