1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

builtin,strconv: append ".0", to float string representations, to ensure clarity (#16079)

This commit is contained in:
Subhomoy Haldar 2022-10-17 13:41:07 +01:00 committed by GitHub
parent 29b1796791
commit 43b9a716c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 98 additions and 74 deletions

View File

@ -1,6 +1,7 @@
## V 0.3.2
*Not yet released*
- Remove the need for the `[console]` attribute in Windows GUI apps.
- All floats outputs now have `.0` conditionally appended to them to improve clarity.
## V 0.3.1
*31 Aug 2022*

View File

@ -19,10 +19,10 @@ pub fn (x f64) str() string {
f: x
}
if f.u == strconv.double_minus_zero {
return '-0'
return '-0.0'
}
if f.u == strconv.double_plus_zero {
return '0'
return '0.0'
}
}
abs_x := f64_abs(x)
@ -37,11 +37,11 @@ pub fn (x f64) str() string {
[inline]
pub fn (x f64) strg() string {
if x == 0 {
return '0'
return '0.0'
}
abs_x := f64_abs(x)
if abs_x >= 0.0001 && abs_x < 1.0e6 {
return strconv.f64_to_str_l_no_dot(x)
return strconv.f64_to_str_l_with_dot(x)
} else {
return strconv.ftoa_64(x)
}
@ -85,10 +85,10 @@ pub fn (x f32) str() string {
f: x
}
if f.u == strconv.single_minus_zero {
return '-0'
return '-0.'
}
if f.u == strconv.single_plus_zero {
return '0'
return '0.'
}
}
abs_x := f32_abs(x)
@ -103,11 +103,11 @@ pub fn (x f32) str() string {
[inline]
pub fn (x f32) strg() string {
if x == 0 {
return '0'
return '0.0'
}
abs_x := f32_abs(x)
if abs_x >= 0.0001 && abs_x < 1.0e6 {
return strconv.f32_to_str_l_no_dot(x)
return strconv.f32_to_str_l_with_dot(x)
} else {
return strconv.ftoa_32(x)
}

View File

@ -2,7 +2,7 @@ fn test_map_of_f32() {
mut m32 := map[f32]string{}
m32[1.0] = 'one'
println(m32)
assert '$m32' == r"{1.: 'one'}"
assert '$m32' == r"{1.0: 'one'}"
for k, v in m32 {
assert typeof(k).name == 'f32'
assert typeof(v).name == 'string'
@ -17,7 +17,7 @@ fn test_map_of_f64() {
}
m64[1.0] = 'one'
println(m64)
assert '$m64' == r"{3.14: 'pi', 1.: 'one'}"
assert '$m64' == r"{3.14: 'pi', 1.0: 'one'}"
for k, v in m64 {
assert typeof(k).name == 'f64'
assert typeof(v).name == 'string'

View File

@ -190,11 +190,11 @@ fn test_signed_cast() {
mut u := strconv.Float64u{
u: strconv.double_plus_zero
}
assert '${u.f:g}' == '0'
assert '${u.f:G}' == '0'
assert '${u.f:g}' == '0.0'
assert '${u.f:G}' == '0.0'
u.u = strconv.double_minus_zero
assert '${u.f:g}' == '0'
assert '${u.f:G}' == '0'
assert '${u.f:g}' == '0.0'
assert '${u.f:G}' == '0.0'
u.u = strconv.double_plus_infinity
assert '${u.f:g}' == '+inf'
assert '${u.f:G}' == '+INF'
@ -206,11 +206,11 @@ fn test_signed_cast() {
mut u := strconv.Float32u{
u: strconv.single_plus_zero
}
assert '${u.f:g}' == '0'
assert '${u.f:G}' == '0'
assert '${u.f:g}' == '0.0'
assert '${u.f:G}' == '0.0'
u.u = strconv.single_minus_zero
assert '${u.f:g}' == '0'
assert '${u.f:G}' == '0'
assert '${u.f:g}' == '0.0'
assert '${u.f:G}' == '0.0'
u.u = strconv.single_plus_infinity
assert '${u.f:g}' == '+inf'
assert '${u.f:G}' == '+INF'

View File

@ -425,7 +425,7 @@ fn test_abs_zero() {
ret2 := abs(0.0)
println(ret2)
assert '$ret2' == '0'
assert '$ret2' == '0.0'
}
fn test_floor() {

View File

@ -138,7 +138,7 @@ fn test_float_to_str() {
// test f32
for c, x in test_cases_f32 {
println(x)
// println(x)
s := strconv.f32_to_str(x, 8)
s1 := exp_result_f32[c]
// println("$s1 $s")
@ -154,10 +154,13 @@ fn test_float_to_str() {
}
// test long format
for exp := 1; exp < 120; exp++ {
assert strconv.f64_to_str_l('1e1'.f64()).len == 4 // '10.0'
assert strconv.f64_to_str_l('1e-1'.f64()).len == 3 // '0.1'
for exp := 2; exp < 120; exp++ {
a := strconv.f64_to_str_l(('1e' + exp.str()).f64())
// println(a)
assert a.len == exp + 1
assert a.len == exp + 3
b := strconv.f64_to_str_l(('1e-' + exp.str()).f64())
// println(b)

View File

@ -36,14 +36,14 @@ pub fn f32_to_str_l(f f32) string {
return res
}
// f32_to_str_l_no_dot returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot.
// The decimal digits after the dot can be omitted.
// f32_to_str_l_with_dot returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot.
// If the decimal digits after the dot are zero, a '.0' is appended for clarity.
//
// Example: assert strconv.f32_to_str_l_no_dot(34.) == '34'
// Example: assert strconv.f32_to_str_l_with_dot(34.) == '34.0'
[manualfree]
pub fn f32_to_str_l_no_dot(f f32) string {
pub fn f32_to_str_l_with_dot(f f32) string {
s := f32_to_str(f, 6)
res := fxx_to_str_l_parse_no_dot(s)
res := fxx_to_str_l_parse_with_dot(s)
unsafe { s.free() }
return res
}
@ -59,14 +59,14 @@ pub fn f64_to_str_l(f f64) string {
return res
}
// f64_to_str_l_no_dot returns `f` as a `string` in decimal notation with a maximum of 18 digits after the dot.
// The decimal digits after the dot can be omitted.
// f64_to_str_l_with_dot returns `f` as a `string` in decimal notation with a maximum of 18 digits after the dot.
// If the decimal digits after the dot are zero, a '.0' is appended for clarity.
//
// Example: assert strconv.f64_to_str_l_no_dot (34.) == '34'
// Example: assert strconv.f64_to_str_l_with_dot (34.) == '34.0'
[manualfree]
pub fn f64_to_str_l_no_dot(f f64) string {
pub fn f64_to_str_l_with_dot(f f64) string {
s := f64_to_str(f, 18)
res := fxx_to_str_l_parse_no_dot(s)
res := fxx_to_str_l_parse_with_dot(s)
unsafe { s.free() }
return res
}
@ -187,23 +187,30 @@ pub fn fxx_to_str_l_parse(s string) string {
i++
}
}
/*
// remove the dot form the numbers like 2.
if r_i > 1 && res[r_i-1] == `.` {
r_i--
// Add a zero after the dot from the numbers like 2.
if r_i > 1 && res[r_i - 1] == `.` {
res[r_i] = `0`
r_i++
} else if `.` !in res {
// If there is no dot, add it with a zero
res[r_i] = `.`
r_i++
res[r_i] = `0`
r_i++
}
*/
res[r_i] = 0
return unsafe { tos(res.data, r_i) }
}
// fxx_to_str_l_parse_no_dot returns a `string` in decimal notation converted from a
// fxx_to_str_l_parse_with_dot returns a `string` in decimal notation converted from a
// floating-point `string` in scientific notation.
// The decimal digits after the dot can be omitted.
// If the decimal digits after the dot are zero, a '.0' is appended for clarity.
//
// Example: assert strconv.fxx_to_str_l_parse_no_dot ('34.e+01') == '340'
// Example: assert strconv.fxx_to_str_l_parse_with_dot ('34.e+01') == '340.0'
[direct_array_access; manualfree]
pub fn fxx_to_str_l_parse_no_dot(s string) string {
pub fn fxx_to_str_l_parse_with_dot(s string) string {
// check for +inf -inf Nan
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
return s.clone()
@ -315,9 +322,16 @@ pub fn fxx_to_str_l_parse_no_dot(s string) string {
}
}
// remove the dot form the numbers like 2.
// Add a zero after the dot from the numbers like 2.
if r_i > 1 && res[r_i - 1] == `.` {
r_i--
res[r_i] = `0`
r_i++
} else if `.` !in res {
// If there is no dot, add it with a zero
res[r_i] = `.`
r_i++
res[r_i] = `0`
r_i++
}
res[r_i] = 0

View File

@ -238,10 +238,16 @@ fn to_burntsushi(value ast.Value) string {
}
if !value.text.starts_with('0x')
&& (value.text.contains('.') || value.text.to_lower().contains('e')) {
mut val := '$value.f64()'.replace('.e+', '.0e') // json notation
if !val.contains('.') && val != '0' { // json notation
mut val := '$value.f64()'.replace('.e+', '.0e') // JSON notation
if !val.contains('.') && val != '0' { // JSON notation
val += '.0'
}
// Since https://github.com/vlang/v/pull/16079 V's string conversion of a zero (0) will
// output "0.0" for float types - the JSON test suite data, however, expects "0" for floats
// The following is a correction for that inconsistency
if val == '0.0' {
val = '0'
}
return '{ "type": "float", "value": "$val" }'
}
v := value.i64()

View File

@ -1,3 +1,3 @@
[1, 0, 0]
[0, 1, 0]
[0, 0, 1]
[1.0, 0.0, 0.0]
[0.0, 1.0, 0.0]
[0.0, 0.0, 1.0]

View File

@ -14,5 +14,5 @@ fn test_assign_map_value_of_fixed_array() {
arr = m['C']
println(arr)
assert '$arr' == '[0, 0]'
assert '$arr' == '[0.0, 0.0]'
}

View File

@ -18,7 +18,7 @@ fn test_fixed_array_const_size() {
fn test_fixed_array_const_u64_size() {
a := [2 * u64_size]f64{}
println(a)
assert '$a' == '[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]'
assert '$a' == '[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]'
}
const n = u64(5_000)

View File

@ -1,6 +1,6 @@
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:30] mi.in_(): 1.
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:31] mi.out(): 2.
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:36] in_put.in_(): 1.
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:37] in_put.out(): 2.
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:39] in_put.in_(): 1.
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:40] in_put.out(): 2.
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:30] mi.in_(): 1.0
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:31] mi.out(): 2.0
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:36] in_put.in_(): 1.0
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:37] in_put.out(): 2.0
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:39] in_put.in_(): 1.0
[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:40] in_put.out(): 2.0

View File

@ -1,12 +1,12 @@
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:19] '$T.name $input': int 1
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:26] '$T.name $input': int 1
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:36] next(1): 0
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:19] '$T.name $input': f64 1.
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:26] '$T.name $input': f64 1.
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:37] next(1.0): 64.
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:36] next(1): 0.0
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:19] '$T.name $input': f64 1.0
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:26] '$T.name $input': f64 1.0
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:37] next(1.0): 64.0
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:19] '$T.name $input': f64 11.1
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:26] '$T.name $input': f64 11.1
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:38] next(11.1): 64.
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:38] next(11.1): 64.0
[vlib/v/tests/inout/dump_nested_generic_fn_call_ref_arg.vv:15] '$T.name $input': Score Score{
ave: 23.4
}

View File

@ -1,6 +1,6 @@
Point(Quad{
x: 1
y: 2
z: 3
w: 1
x: 1.0
y: 2.0
z: 3.0
w: 1.0
})

View File

@ -9,7 +9,7 @@ fn test_empty_interface_string_interpolation() {
b := IEmpty(f32(1))
c := IEmpty(Abc{'abc'})
assert '$a' == 'IEmpty(1)'
assert '$b' == 'IEmpty(1.)'
assert '$b' == 'IEmpty(1.0)'
assert '$c'.starts_with('IEmpty(Abc{')
assert '$c'.contains("x: 'abc'")
assert '$c'.ends_with('})')

View File

@ -13,15 +13,15 @@ fn test_variadic_array_decompose() {
a << Foo{}
input := [0.0, 1.0]
assert a[0].method(...input) == '[0, 1]'
assert a[0].method(...[0.0, 1.0]) == '[0, 1]'
assert a[0].method(...input) == '[0.0, 1.0]'
assert a[0].method(...[0.0, 1.0]) == '[0.0, 1.0]'
}
fn test_variadic_multiple_args() {
mut a := []Element{}
a << Foo{}
assert a[0].method(0.0, 1.0) == '[0, 1]'
assert a[0].method(0.0, 1.0) == '[0.0, 1.0]'
}
interface Animal {}

View File

@ -23,7 +23,7 @@ fn test_float_lit_call_method() {
x5 := 2.e-3.str()
assert x5 == '0.002'
x6 := 5.0.str()
assert x6 == '5.'
assert x6 == '5.0'
// x7 := 5..str() Syntax `5.` is allowed, but do not call method on it (`5..str()` is parsed as a range). Use `5.0.str()` instead.
x8 := 7.345e-7.str()
assert x8 == '7.345e-07'

View File

@ -1 +1 @@
0
0.0

View File

@ -30,7 +30,7 @@ fn test_fixed_array_struct_string_interpolation() {
ctx.vb = [1.1, x, 3.3, 4.4, 5.0, 6.0, 7.0, 8.9]!
s := '$ctx'
assert s.starts_with('Context{')
assert s.contains('vb: [1.1, 2.32, 3.3, 4.4, 5, 6, 7, 8.9]')
assert s.contains('vb: [1.1, 2.32, 3.3, 4.4, 5.0, 6.0, 7.0, 8.9]')
assert s.ends_with('}')
}

View File

@ -76,7 +76,7 @@ fn test_typeof_on_sumtypes() {
assert typeof(c).name == 'MySumType'
assert a.str() == '32'
assert b.str() == '123.'
assert b.str() == '123.0'
assert c.str() == 'FooBar'
}