strconv: float functions cleaning and speed optimization (#10076)
parent
3b062388ba
commit
d60a55d30b
|
@ -1,6 +1,5 @@
|
||||||
module strconv
|
module strconv
|
||||||
|
/*=============================================================================
|
||||||
/*
|
|
||||||
|
|
||||||
f32 to string
|
f32 to string
|
||||||
|
|
||||||
|
@ -18,8 +17,7 @@ Pages 270–282 https://doi.org/10.1145/3192366.3192369
|
||||||
inspired by the Go version here:
|
inspired by the Go version here:
|
||||||
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
|
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
|
||||||
|
|
||||||
*/
|
=============================================================================*/
|
||||||
|
|
||||||
|
|
||||||
// pow of ten table used by n_digit reduction
|
// pow of ten table used by n_digit reduction
|
||||||
const(
|
const(
|
||||||
|
@ -39,11 +37,9 @@ const(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
//=============================================================================
|
||||||
|
// Conversion Functions
|
||||||
Conversion Functions
|
//=============================================================================
|
||||||
|
|
||||||
*/
|
|
||||||
const(
|
const(
|
||||||
mantbits32 = u32(23)
|
mantbits32 = u32(23)
|
||||||
expbits32 = u32(8)
|
expbits32 = u32(8)
|
||||||
|
@ -53,11 +49,13 @@ const(
|
||||||
|
|
||||||
// max 46 char
|
// max 46 char
|
||||||
// -3.40282346638528859811704183484516925440e+38
|
// -3.40282346638528859811704183484516925440e+38
|
||||||
|
[direct_array_access]
|
||||||
pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string {
|
pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
n_digit := i_n_digit + 1
|
n_digit := i_n_digit + 1
|
||||||
pad_digit := i_pad_digit + 1
|
pad_digit := i_pad_digit + 1
|
||||||
mut out := d.m
|
mut out := d.m
|
||||||
mut out_len := decimal_len_32(out)
|
//mut out_len := decimal_len_32(out)
|
||||||
|
mut out_len := dec_digits(out)
|
||||||
out_len_original := out_len
|
out_len_original := out_len
|
||||||
|
|
||||||
mut fw_zeros := 0
|
mut fw_zeros := 0
|
||||||
|
@ -119,15 +117,6 @@ pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string
|
||||||
fw_zeros--
|
fw_zeros--
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
x=0
|
|
||||||
for x<buf.len {
|
|
||||||
C.printf("d:%c\n",buf[x])
|
|
||||||
x++
|
|
||||||
}
|
|
||||||
C.printf("\n")
|
|
||||||
*/
|
|
||||||
|
|
||||||
buf[i]=`e`
|
buf[i]=`e`
|
||||||
i++
|
i++
|
||||||
|
|
||||||
|
@ -150,13 +139,6 @@ pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string
|
||||||
i++
|
i++
|
||||||
buf[i]=0
|
buf[i]=0
|
||||||
|
|
||||||
/*
|
|
||||||
x=0
|
|
||||||
for x<buf.len {
|
|
||||||
C.printf("d:%c\n",buf[x])
|
|
||||||
x++
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return unsafe {
|
return unsafe {
|
||||||
tos(byteptr(&buf[0]), i)
|
tos(byteptr(&buf[0]), i)
|
||||||
}
|
}
|
||||||
|
@ -233,7 +215,7 @@ pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
|
||||||
// The largest power of 5 that fits in 24 bits is 5^10,
|
// The largest power of 5 that fits in 24 bits is 5^10,
|
||||||
// but q <= 9 seems to be safe as well. Only one of mp,
|
// but q <= 9 seems to be safe as well. Only one of mp,
|
||||||
// mv, and mm can be a multiple of 5, if any.
|
// mv, and mm can be a multiple of 5, if any.
|
||||||
if mv%5 == 0 {
|
if mv % 5 == 0 {
|
||||||
vr_is_trailing_zeros = multiple_of_power_of_five_32(mv, q)
|
vr_is_trailing_zeros = multiple_of_power_of_five_32(mv, q)
|
||||||
} else if accept_bounds {
|
} else if accept_bounds {
|
||||||
vm_is_trailing_zeros = multiple_of_power_of_five_32(mm, q)
|
vm_is_trailing_zeros = multiple_of_power_of_five_32(mm, q)
|
||||||
|
@ -327,15 +309,19 @@ pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
|
||||||
return Dec32{m: out e: e10 + removed}
|
return Dec32{m: out e: e10 + removed}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// String Functions
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
// f32_to_str return a string in scientific notation with max n_digit after the dot
|
// f32_to_str return a string in scientific notation with max n_digit after the dot
|
||||||
pub fn f32_to_str(f f32, n_digit int) string {
|
pub fn f32_to_str(f f32, n_digit int) string {
|
||||||
mut u1 := Uf32{}
|
mut u1 := Uf32{}
|
||||||
u1.f = f
|
u1.f = f
|
||||||
u := unsafe {u1.u}
|
u := unsafe {u1.u}
|
||||||
|
|
||||||
neg := (u>>(mantbits32+expbits32)) != 0
|
neg := (u >> (mantbits32 + expbits32)) != 0
|
||||||
mant := u & ((u32(1)<<mantbits32) - u32(1))
|
mant := u & ((u32(1) << mantbits32) - u32(1))
|
||||||
exp := (u >> mantbits32) & ((u32(1)<<expbits32) - u32(1))
|
exp := (u >> mantbits32) & ((u32(1) << expbits32) - u32(1))
|
||||||
|
|
||||||
//println("${neg} ${mant} e ${exp-bias32}")
|
//println("${neg} ${mant} e ${exp-bias32}")
|
||||||
|
|
||||||
|
@ -360,9 +346,9 @@ pub fn f32_to_str_pad(f f32, n_digit int) string {
|
||||||
u1.f = f
|
u1.f = f
|
||||||
u := unsafe {u1.u}
|
u := unsafe {u1.u}
|
||||||
|
|
||||||
neg := (u>>(mantbits32+expbits32)) != 0
|
neg := (u >> (mantbits32 + expbits32)) != 0
|
||||||
mant := u & ((u32(1)<<mantbits32) - u32(1))
|
mant := u & ((u32(1) << mantbits32) - u32(1))
|
||||||
exp := (u >> mantbits32) & ((u32(1)<<expbits32) - u32(1))
|
exp := (u >> mantbits32) & ((u32(1) << expbits32) - u32(1))
|
||||||
|
|
||||||
//println("${neg} ${mant} e ${exp-bias32}")
|
//println("${neg} ${mant} e ${exp-bias32}")
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
module strconv
|
module strconv
|
||||||
|
/*=============================================================================
|
||||||
|
|
||||||
/*
|
f64 to string
|
||||||
|
|
||||||
f32 to string
|
|
||||||
|
|
||||||
Copyright (c) 2019-2021 Dario Deledda. All rights reserved.
|
Copyright (c) 2019-2021 Dario Deledda. All rights reserved.
|
||||||
Use of this source code is governed by an MIT license
|
Use of this source code is governed by an MIT license
|
||||||
|
@ -18,7 +17,7 @@ Pages 270–282 https://doi.org/10.1145/3192366.3192369
|
||||||
inspired by the Go version here:
|
inspired by the Go version here:
|
||||||
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
|
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
|
||||||
|
|
||||||
*/
|
=============================================================================*/
|
||||||
|
|
||||||
// pow of ten table used by n_digit reduction
|
// pow of ten table used by n_digit reduction
|
||||||
const(
|
const(
|
||||||
|
@ -46,11 +45,9 @@ const(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
//=============================================================================
|
||||||
|
// Conversion Functions
|
||||||
Conversion Functions
|
//=============================================================================
|
||||||
|
|
||||||
*/
|
|
||||||
const(
|
const(
|
||||||
mantbits64 = u32(52)
|
mantbits64 = u32(52)
|
||||||
expbits64 = u32(11)
|
expbits64 = u32(11)
|
||||||
|
@ -58,12 +55,14 @@ const(
|
||||||
maxexp64 = 2047
|
maxexp64 = 2047
|
||||||
)
|
)
|
||||||
|
|
||||||
|
[direct_array_access]
|
||||||
fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
mut n_digit := i_n_digit + 1
|
mut n_digit := i_n_digit + 1
|
||||||
pad_digit := i_pad_digit + 1
|
pad_digit := i_pad_digit + 1
|
||||||
mut out := d.m
|
mut out := d.m
|
||||||
mut d_exp := d.e
|
mut d_exp := d.e
|
||||||
mut out_len := decimal_len_64(out)
|
// mut out_len := decimal_len_64(out)
|
||||||
|
mut out_len := dec_digits(out)
|
||||||
out_len_original := out_len
|
out_len_original := out_len
|
||||||
|
|
||||||
mut fw_zeros := 0
|
mut fw_zeros := 0
|
||||||
|
@ -75,7 +74,7 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
mut i := 0
|
mut i := 0
|
||||||
|
|
||||||
if neg {
|
if neg {
|
||||||
buf[i]=`-`
|
buf[i] = `-`
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,9 +87,9 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
if n_digit < out_len {
|
if n_digit < out_len {
|
||||||
//println("out:[$out]")
|
//println("out:[$out]")
|
||||||
out += ten_pow_table_64[out_len - n_digit - 1] * 5 // round to up
|
out += ten_pow_table_64[out_len - n_digit - 1] * 5 // round to up
|
||||||
out /= ten_pow_table_64[out_len - n_digit ]
|
out /= ten_pow_table_64[out_len - n_digit]
|
||||||
//println("out1:[$out] ${d.m / ten_pow_table_64[out_len - n_digit ]}")
|
//println("out1:[$out] ${d.m / ten_pow_table_64[out_len - n_digit ]}")
|
||||||
if d.m / ten_pow_table_64[out_len - n_digit ] < out {
|
if d.m / ten_pow_table_64[out_len - n_digit] < out {
|
||||||
d_exp++
|
d_exp++
|
||||||
n_digit++
|
n_digit++
|
||||||
}
|
}
|
||||||
|
@ -103,8 +102,8 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
|
|
||||||
y := i + out_len
|
y := i + out_len
|
||||||
mut x := 0
|
mut x := 0
|
||||||
for x < (out_len-disp-1) {
|
for x < (out_len - disp - 1) {
|
||||||
buf[y - x] = `0` + byte(out%10)
|
buf[y - x] = `0` + byte(out % 10)
|
||||||
out /= 10
|
out /= 10
|
||||||
i++
|
i++
|
||||||
x++
|
x++
|
||||||
|
@ -114,7 +113,7 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
if i_n_digit == 0 {
|
if i_n_digit == 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
buf[i]=0
|
buf[i]=0
|
||||||
return tos(byteptr(&buf[0]), i)
|
return tos(byteptr(&buf[0]), i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +124,7 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if y-x >= 0 {
|
if y-x >= 0 {
|
||||||
buf[y - x] = `0` + byte(out%10)
|
buf[y - x] = `0` + byte(out % 10)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,15 +134,6 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
fw_zeros--
|
fw_zeros--
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
x=0
|
|
||||||
for x<buf.len {
|
|
||||||
C.printf("d:%c\n",buf[x])
|
|
||||||
x++
|
|
||||||
}
|
|
||||||
C.printf("\n")
|
|
||||||
*/
|
|
||||||
|
|
||||||
buf[i]=`e`
|
buf[i]=`e`
|
||||||
i++
|
i++
|
||||||
|
|
||||||
|
@ -172,14 +162,6 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
|
||||||
i++
|
i++
|
||||||
buf[i]=0
|
buf[i]=0
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
x=0
|
|
||||||
for x<buf.len {
|
|
||||||
C.printf("d:%c\n",buf[x])
|
|
||||||
x++
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return unsafe {
|
return unsafe {
|
||||||
tos(byteptr(&buf[0]), i)
|
tos(byteptr(&buf[0]), i)
|
||||||
}
|
}
|
||||||
|
@ -216,7 +198,7 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
|
||||||
m2 = mant
|
m2 = mant
|
||||||
} else {
|
} else {
|
||||||
e2 = int(exp) - bias64 - int(mantbits64) - 2
|
e2 = int(exp) - bias64 - int(mantbits64) - 2
|
||||||
m2 = (u64(1)<<mantbits64) | mant
|
m2 = (u64(1) << mantbits64) | mant
|
||||||
}
|
}
|
||||||
even := (m2 & 1) == 0
|
even := (m2 & 1) == 0
|
||||||
accept_bounds := even
|
accept_bounds := even
|
||||||
|
@ -249,14 +231,14 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
|
||||||
// Smaller values may still be safe, but it's more
|
// Smaller values may still be safe, but it's more
|
||||||
// difficult to reason about them. Only one of mp, mv,
|
// difficult to reason about them. Only one of mp, mv,
|
||||||
// and mm can be a multiple of 5, if any.
|
// and mm can be a multiple of 5, if any.
|
||||||
if mv%5 == 0 {
|
if mv % 5 == 0 {
|
||||||
vr_is_trailing_zeros = multiple_of_power_of_five_64(mv, q)
|
vr_is_trailing_zeros = multiple_of_power_of_five_64(mv, q)
|
||||||
} else if accept_bounds {
|
} else if accept_bounds {
|
||||||
// Same as min(e2 + (^mm & 1), pow5Factor64(mm)) >= q
|
// Same as min(e2 + (^mm & 1), pow5Factor64(mm)) >= q
|
||||||
// <=> e2 + (^mm & 1) >= q && pow5Factor64(mm) >= q
|
// <=> e2 + (^mm & 1) >= q && pow5Factor64(mm) >= q
|
||||||
// <=> true && pow5Factor64(mm) >= q, since e2 >= q.
|
// <=> true && pow5Factor64(mm) >= q, since e2 >= q.
|
||||||
vm_is_trailing_zeros = multiple_of_power_of_five_64(mv-1-mm_shift, q)
|
vm_is_trailing_zeros = multiple_of_power_of_five_64(mv - 1 - mm_shift, q)
|
||||||
} else if multiple_of_power_of_five_64(mv+2, q) {
|
} else if multiple_of_power_of_five_64(mv + 2, q) {
|
||||||
vp--
|
vp--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,7 +284,7 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
|
||||||
// General case, which happens rarely (~0.7%).
|
// General case, which happens rarely (~0.7%).
|
||||||
for {
|
for {
|
||||||
vp_div_10 := vp / 10
|
vp_div_10 := vp / 10
|
||||||
vm_div_10 := vm / 10
|
vm_div_10 := vm / 10
|
||||||
if vp_div_10 <= vm_div_10 {
|
if vp_div_10 <= vm_div_10 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -376,15 +358,19 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
|
||||||
return Dec64{m: out, e: e10 + removed}
|
return Dec64{m: out, e: e10 + removed}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// String Functions
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
// f64_to_str return a string in scientific notation with max n_digit after the dot
|
// f64_to_str return a string in scientific notation with max n_digit after the dot
|
||||||
pub fn f64_to_str(f f64, n_digit int) string {
|
pub fn f64_to_str(f f64, n_digit int) string {
|
||||||
mut u1 := Uf64{}
|
mut u1 := Uf64{}
|
||||||
u1.f = f
|
u1.f = f
|
||||||
u := unsafe {u1.u}
|
u := unsafe {u1.u}
|
||||||
|
|
||||||
neg := (u>>(mantbits64+expbits64)) != 0
|
neg := (u >> (mantbits64 + expbits64)) != 0
|
||||||
mant := u & ((u64(1)<<mantbits64) - u64(1))
|
mant := u & ((u64(1) << mantbits64) - u64(1))
|
||||||
exp := (u >> mantbits64) & ((u64(1)<<expbits64) - u64(1))
|
exp := (u >> mantbits64) & ((u64(1) << expbits64) - u64(1))
|
||||||
//println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}")
|
//println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}")
|
||||||
|
|
||||||
// Exit early for easy cases.
|
// Exit early for easy cases.
|
||||||
|
@ -407,9 +393,9 @@ pub fn f64_to_str_pad(f f64, n_digit int) string {
|
||||||
u1.f = f
|
u1.f = f
|
||||||
u := unsafe {u1.u}
|
u := unsafe {u1.u}
|
||||||
|
|
||||||
neg := (u>>(mantbits64+expbits64)) != 0
|
neg := (u >> (mantbits64 + expbits64)) != 0
|
||||||
mant := u & ((u64(1)<<mantbits64) - u64(1))
|
mant := u & ((u64(1) << mantbits64) - u64(1))
|
||||||
exp := (u >> mantbits64) & ((u64(1)<<expbits64) - u64(1))
|
exp := (u >> mantbits64) & ((u64(1) << expbits64) - u64(1))
|
||||||
//println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}")
|
//println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}")
|
||||||
|
|
||||||
// Exit early for easy cases.
|
// Exit early for easy cases.
|
||||||
|
|
Loading…
Reference in New Issue