593 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			593 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			V
		
	
	
| module strconv
 | ||
| 
 | ||
| import math.bits
 | ||
| // import math
 | ||
| 
 | ||
| /*
 | ||
| f32/f64 to string utilities
 | ||
| 
 | ||
| Copyright (c) 2019-2021 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 the f32/f64 to string utilities functions
 | ||
| 
 | ||
| These functions are based on the work of:
 | ||
| Publication:PLDI 2018: Proceedings of the 39th ACM SIGPLAN
 | ||
| Conference on Programming Language Design and ImplementationJune 2018
 | ||
| Pages 270–282 https://doi.org/10.1145/3192366.3192369
 | ||
| 
 | ||
| inspired by the Go version here:
 | ||
| https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
 | ||
| */
 | ||
| 
 | ||
| // General Utilities
 | ||
| [if debug_strconv ?]
 | ||
| fn assert1(t bool, msg string) {
 | ||
| 	if !t {
 | ||
| 		panic(msg)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| [inline]
 | ||
| fn bool_to_int(b bool) int {
 | ||
| 	if b {
 | ||
| 		return 1
 | ||
| 	}
 | ||
| 	return 0
 | ||
| }
 | ||
| 
 | ||
| [inline]
 | ||
| fn bool_to_u32(b bool) u32 {
 | ||
| 	if b {
 | ||
| 		return u32(1)
 | ||
| 	}
 | ||
| 	return u32(0)
 | ||
| }
 | ||
| 
 | ||
| [inline]
 | ||
| fn bool_to_u64(b bool) u64 {
 | ||
| 	if b {
 | ||
| 		return u64(1)
 | ||
| 	}
 | ||
| 	return u64(0)
 | ||
| }
 | ||
| 
 | ||
| fn get_string_special(neg bool, expZero bool, mantZero bool) string {
 | ||
| 	if !mantZero {
 | ||
| 		return 'nan'
 | ||
| 	}
 | ||
| 	if !expZero {
 | ||
| 		if neg {
 | ||
| 			return '-inf'
 | ||
| 		} else {
 | ||
| 			return '+inf'
 | ||
| 		}
 | ||
| 	}
 | ||
| 	if neg {
 | ||
| 		return '-0e+00'
 | ||
| 	}
 | ||
| 	return '0e+00'
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
| 32 bit functions
 | ||
| */
 | ||
| // decimal_len_32 return the number of decimal digits of the input
 | ||
| [deprecated]
 | ||
| pub fn decimal_len_32(u u32) int {
 | ||
| 	// Function precondition: u is not a 10-digit number.
 | ||
| 	// (9 digits are sufficient for round-tripping.)
 | ||
| 	// This benchmarked faster than the log2 approach used for u64.
 | ||
| 	assert1(u < 1000000000, 'too big')
 | ||
| 
 | ||
| 	if u >= 100000000 {
 | ||
| 		return 9
 | ||
| 	} else if u >= 10000000 {
 | ||
| 		return 8
 | ||
| 	} else if u >= 1000000 {
 | ||
| 		return 7
 | ||
| 	} else if u >= 100000 {
 | ||
| 		return 6
 | ||
| 	} else if u >= 10000 {
 | ||
| 		return 5
 | ||
| 	} else if u >= 1000 {
 | ||
| 		return 4
 | ||
| 	} else if u >= 100 {
 | ||
| 		return 3
 | ||
| 	} else if u >= 10 {
 | ||
| 		return 2
 | ||
| 	}
 | ||
| 	return 1
 | ||
| }
 | ||
| 
 | ||
| fn mul_shift_32(m u32, mul u64, ishift int) u32 {
 | ||
| 	// QTODO
 | ||
| 	// assert ishift > 32
 | ||
| 
 | ||
| 	hi, lo := bits.mul_64(u64(m), mul)
 | ||
| 	shifted_sum := (lo >> u64(ishift)) + (hi << u64(64 - ishift))
 | ||
| 	assert1(shifted_sum <= 2147483647, 'shiftedSum <= math.max_u32')
 | ||
| 	return u32(shifted_sum)
 | ||
| }
 | ||
| 
 | ||
| fn mul_pow5_invdiv_pow2(m u32, q u32, j int) u32 {
 | ||
| 	return mul_shift_32(m, pow5_inv_split_32[q], j)
 | ||
| }
 | ||
| 
 | ||
| fn mul_pow5_div_pow2(m u32, i u32, j int) u32 {
 | ||
| 	return mul_shift_32(m, pow5_split_32[i], j)
 | ||
| }
 | ||
| 
 | ||
| fn pow5_factor_32(i_v u32) u32 {
 | ||
| 	mut v := i_v
 | ||
| 	for n := u32(0); true; n++ {
 | ||
| 		q := v / 5
 | ||
| 		r := v % 5
 | ||
| 		if r != 0 {
 | ||
| 			return n
 | ||
| 		}
 | ||
| 		v = q
 | ||
| 	}
 | ||
| 	return v
 | ||
| }
 | ||
| 
 | ||
| // multiple_of_power_of_five_32 reports whether v is divisible by 5^p.
 | ||
| fn multiple_of_power_of_five_32(v u32, p u32) bool {
 | ||
| 	return pow5_factor_32(v) >= p
 | ||
| }
 | ||
| 
 | ||
| // multiple_of_power_of_two_32 reports whether v is divisible by 2^p.
 | ||
| fn multiple_of_power_of_two_32(v u32, p u32) bool {
 | ||
| 	return u32(bits.trailing_zeros_32(v)) >= p
 | ||
| }
 | ||
| 
 | ||
| // log10_pow2 returns floor(log_10(2^e)).
 | ||
| fn log10_pow2(e int) u32 {
 | ||
| 	// The first value this approximation fails for is 2^1651
 | ||
| 	// which is just greater than 10^297.
 | ||
| 	assert1(e >= 0, 'e >= 0')
 | ||
| 	assert1(e <= 1650, 'e <= 1650')
 | ||
| 	return (u32(e) * 78913) >> 18
 | ||
| }
 | ||
| 
 | ||
| // log10_pow5 returns floor(log_10(5^e)).
 | ||
| fn log10_pow5(e int) u32 {
 | ||
| 	// The first value this approximation fails for is 5^2621
 | ||
| 	// which is just greater than 10^1832.
 | ||
| 	assert1(e >= 0, 'e >= 0')
 | ||
| 	assert1(e <= 2620, 'e <= 2620')
 | ||
| 	return (u32(e) * 732923) >> 20
 | ||
| }
 | ||
| 
 | ||
| // pow5_bits returns ceil(log_2(5^e)), or else 1 if e==0.
 | ||
| fn pow5_bits(e int) int {
 | ||
| 	// This approximation works up to the point that the multiplication
 | ||
| 	// overflows at e = 3529. If the multiplication were done in 64 bits,
 | ||
| 	// it would fail at 5^4004 which is just greater than 2^9297.
 | ||
| 	assert1(e >= 0, 'e >= 0')
 | ||
| 	assert1(e <= 3528, 'e <= 3528')
 | ||
| 	return int(((u32(e) * 1217359) >> 19) + 1)
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
| 64 bit functions
 | ||
| */
 | ||
| 
 | ||
| // decimal_len_64 return the number of decimal digits of the input
 | ||
| [deprecated]
 | ||
| pub fn decimal_len_64(u u64) int {
 | ||
| 	// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
 | ||
| 	log2 := 64 - bits.leading_zeros_64(u) - 1
 | ||
| 	t := (log2 + 1) * 1233 >> 12
 | ||
| 	return t - bool_to_int(u < powers_of_10[t]) + 1
 | ||
| }
 | ||
| 
 | ||
| fn shift_right_128(v Uint128, shift int) u64 {
 | ||
| 	// The shift value is always modulo 64.
 | ||
| 	// In the current implementation of the 64-bit version
 | ||
| 	// of Ryu, the shift value is always < 64.
 | ||
| 	// (It is in the range [2, 59].)
 | ||
| 	// Check this here in case a future change requires larger shift
 | ||
| 	// values. In this case this function needs to be adjusted.
 | ||
| 	assert1(shift < 64, 'shift < 64')
 | ||
| 	return (v.hi << u64(64 - shift)) | (v.lo >> u32(shift))
 | ||
| }
 | ||
| 
 | ||
| fn mul_shift_64(m u64, mul Uint128, shift int) u64 {
 | ||
| 	hihi, hilo := bits.mul_64(m, mul.hi)
 | ||
| 	lohi, _ := bits.mul_64(m, mul.lo)
 | ||
| 	mut sum := Uint128{
 | ||
| 		lo: lohi + hilo
 | ||
| 		hi: hihi
 | ||
| 	}
 | ||
| 	if sum.lo < lohi {
 | ||
| 		sum.hi++ // overflow
 | ||
| 	}
 | ||
| 	return shift_right_128(sum, shift - 64)
 | ||
| }
 | ||
| 
 | ||
| fn pow5_factor_64(v_i u64) u32 {
 | ||
| 	mut v := v_i
 | ||
| 	for n := u32(0); true; n++ {
 | ||
| 		q := v / 5
 | ||
| 		r := v % 5
 | ||
| 		if r != 0 {
 | ||
| 			return n
 | ||
| 		}
 | ||
| 		v = q
 | ||
| 	}
 | ||
| 	return u32(0)
 | ||
| }
 | ||
| 
 | ||
| fn multiple_of_power_of_five_64(v u64, p u32) bool {
 | ||
| 	return pow5_factor_64(v) >= p
 | ||
| }
 | ||
| 
 | ||
| fn multiple_of_power_of_two_64(v u64, p u32) bool {
 | ||
| 	return u32(bits.trailing_zeros_64(v)) >= p
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
| f64 to string with string format
 | ||
| */
 | ||
| 
 | ||
| // TODO: Investigate precision issues
 | ||
| // f32_to_str_l return a string with the f32 converted in a string in decimal notation
 | ||
| [manualfree]
 | ||
| pub fn f32_to_str_l(f f32) string {
 | ||
| 	s := f32_to_str(f, 6)
 | ||
| 	res := fxx_to_str_l_parse(s)
 | ||
| 	unsafe { s.free() }
 | ||
| 	return res
 | ||
| }
 | ||
| 
 | ||
| [manualfree]
 | ||
| pub fn f32_to_str_l_no_dot(f f32) string {
 | ||
| 	s := f32_to_str(f, 6)
 | ||
| 	res := fxx_to_str_l_parse_no_dot(s)
 | ||
| 	unsafe { s.free() }
 | ||
| 	return res
 | ||
| }
 | ||
| 
 | ||
| [manualfree]
 | ||
| pub fn f64_to_str_l(f f64) string {
 | ||
| 	s := f64_to_str(f, 18)
 | ||
| 	res := fxx_to_str_l_parse(s)
 | ||
| 	unsafe { s.free() }
 | ||
| 	return res
 | ||
| }
 | ||
| 
 | ||
| [manualfree]
 | ||
| pub fn f64_to_str_l_no_dot(f f64) string {
 | ||
| 	s := f64_to_str(f, 18)
 | ||
| 	res := fxx_to_str_l_parse_no_dot(s)
 | ||
| 	unsafe { s.free() }
 | ||
| 	return res
 | ||
| }
 | ||
| 
 | ||
| // f64_to_str_l return a string with the f64 converted in a string in decimal notation
 | ||
| [manualfree]
 | ||
| pub fn fxx_to_str_l_parse(s string) string {
 | ||
| 	// check for +inf -inf Nan
 | ||
| 	if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
 | ||
| 		return s.clone()
 | ||
| 	}
 | ||
| 
 | ||
| 	m_sgn_flag := false
 | ||
| 	mut sgn := 1
 | ||
| 	mut b := [26]byte{}
 | ||
| 	mut d_pos := 1
 | ||
| 	mut i := 0
 | ||
| 	mut i1 := 0
 | ||
| 	mut exp := 0
 | ||
| 	mut exp_sgn := 1
 | ||
| 
 | ||
| 	// get sign and decimal parts
 | ||
| 	for c in s {
 | ||
| 		if c == `-` {
 | ||
| 			sgn = -1
 | ||
| 			i++
 | ||
| 		} else if c == `+` {
 | ||
| 			sgn = 1
 | ||
| 			i++
 | ||
| 		} else if c >= `0` && c <= `9` {
 | ||
| 			b[i1] = c
 | ||
| 			i1++
 | ||
| 			i++
 | ||
| 		} else if c == `.` {
 | ||
| 			if sgn > 0 {
 | ||
| 				d_pos = i
 | ||
| 			} else {
 | ||
| 				d_pos = i - 1
 | ||
| 			}
 | ||
| 			i++
 | ||
| 		} else if c == `e` {
 | ||
| 			i++
 | ||
| 			break
 | ||
| 		} else {
 | ||
| 			return 'Float conversion error!!'
 | ||
| 		}
 | ||
| 	}
 | ||
| 	b[i1] = 0
 | ||
| 
 | ||
| 	// get exponent
 | ||
| 	if s[i] == `-` {
 | ||
| 		exp_sgn = -1
 | ||
| 		i++
 | ||
| 	} else if s[i] == `+` {
 | ||
| 		exp_sgn = 1
 | ||
| 		i++
 | ||
| 	}
 | ||
| 
 | ||
| 	mut c := i
 | ||
| 	for c < s.len {
 | ||
| 		exp = exp * 10 + int(s[c] - `0`)
 | ||
| 		c++
 | ||
| 	}
 | ||
| 
 | ||
| 	// allocate exp+32 chars for the return string
 | ||
| 	mut res := []byte{len: exp + 32, init: 0}
 | ||
| 	mut r_i := 0 // result string buffer index
 | ||
| 
 | ||
| 	// println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
 | ||
| 
 | ||
| 	if sgn == 1 {
 | ||
| 		if m_sgn_flag {
 | ||
| 			res[r_i] = `+`
 | ||
| 			r_i++
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		res[r_i] = `-`
 | ||
| 		r_i++
 | ||
| 	}
 | ||
| 
 | ||
| 	i = 0
 | ||
| 	if exp_sgn >= 0 {
 | ||
| 		for b[i] != 0 {
 | ||
| 			res[r_i] = b[i]
 | ||
| 			r_i++
 | ||
| 			i++
 | ||
| 			if i >= d_pos && exp >= 0 {
 | ||
| 				if exp == 0 {
 | ||
| 					res[r_i] = `.`
 | ||
| 					r_i++
 | ||
| 				}
 | ||
| 				exp--
 | ||
| 			}
 | ||
| 		}
 | ||
| 		for exp >= 0 {
 | ||
| 			res[r_i] = `0`
 | ||
| 			r_i++
 | ||
| 			exp--
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		mut dot_p := true
 | ||
| 		for exp > 0 {
 | ||
| 			res[r_i] = `0`
 | ||
| 			r_i++
 | ||
| 			exp--
 | ||
| 			if dot_p {
 | ||
| 				res[r_i] = `.`
 | ||
| 				r_i++
 | ||
| 				dot_p = false
 | ||
| 			}
 | ||
| 		}
 | ||
| 		for b[i] != 0 {
 | ||
| 			res[r_i] = b[i]
 | ||
| 			r_i++
 | ||
| 			i++
 | ||
| 		}
 | ||
| 	}
 | ||
| 	/*
 | ||
| 	// remove the dot form the numbers like 2.
 | ||
| 	if r_i > 1 && res[r_i-1] == `.` {
 | ||
| 		r_i--
 | ||
| 	}
 | ||
| 	*/
 | ||
| 	res[r_i] = 0
 | ||
| 	return unsafe { tos(res.data, r_i) }
 | ||
| }
 | ||
| 
 | ||
| // f64_to_str_l return a string with the f64 converted in a string in decimal notation
 | ||
| [manualfree]
 | ||
| pub fn fxx_to_str_l_parse_no_dot(s string) string {
 | ||
| 	// check for +inf -inf Nan
 | ||
| 	if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
 | ||
| 		return s.clone()
 | ||
| 	}
 | ||
| 
 | ||
| 	m_sgn_flag := false
 | ||
| 	mut sgn := 1
 | ||
| 	mut b := [26]byte{}
 | ||
| 	mut d_pos := 1
 | ||
| 	mut i := 0
 | ||
| 	mut i1 := 0
 | ||
| 	mut exp := 0
 | ||
| 	mut exp_sgn := 1
 | ||
| 
 | ||
| 	// get sign and decimal parts
 | ||
| 	for c in s {
 | ||
| 		if c == `-` {
 | ||
| 			sgn = -1
 | ||
| 			i++
 | ||
| 		} else if c == `+` {
 | ||
| 			sgn = 1
 | ||
| 			i++
 | ||
| 		} else if c >= `0` && c <= `9` {
 | ||
| 			b[i1] = c
 | ||
| 			i1++
 | ||
| 			i++
 | ||
| 		} else if c == `.` {
 | ||
| 			if sgn > 0 {
 | ||
| 				d_pos = i
 | ||
| 			} else {
 | ||
| 				d_pos = i - 1
 | ||
| 			}
 | ||
| 			i++
 | ||
| 		} else if c == `e` {
 | ||
| 			i++
 | ||
| 			break
 | ||
| 		} else {
 | ||
| 			return 'Float conversion error!!'
 | ||
| 		}
 | ||
| 	}
 | ||
| 	b[i1] = 0
 | ||
| 
 | ||
| 	// get exponent
 | ||
| 	if s[i] == `-` {
 | ||
| 		exp_sgn = -1
 | ||
| 		i++
 | ||
| 	} else if s[i] == `+` {
 | ||
| 		exp_sgn = 1
 | ||
| 		i++
 | ||
| 	}
 | ||
| 
 | ||
| 	mut c := i
 | ||
| 	for c < s.len {
 | ||
| 		exp = exp * 10 + int(s[c] - `0`)
 | ||
| 		c++
 | ||
| 	}
 | ||
| 
 | ||
| 	// allocate exp+32 chars for the return string
 | ||
| 	mut res := []byte{len: exp + 32, init: 0}
 | ||
| 	mut r_i := 0 // result string buffer index
 | ||
| 
 | ||
| 	// println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
 | ||
| 
 | ||
| 	if sgn == 1 {
 | ||
| 		if m_sgn_flag {
 | ||
| 			res[r_i] = `+`
 | ||
| 			r_i++
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		res[r_i] = `-`
 | ||
| 		r_i++
 | ||
| 	}
 | ||
| 
 | ||
| 	i = 0
 | ||
| 	if exp_sgn >= 0 {
 | ||
| 		for b[i] != 0 {
 | ||
| 			res[r_i] = b[i]
 | ||
| 			r_i++
 | ||
| 			i++
 | ||
| 			if i >= d_pos && exp >= 0 {
 | ||
| 				if exp == 0 {
 | ||
| 					res[r_i] = `.`
 | ||
| 					r_i++
 | ||
| 				}
 | ||
| 				exp--
 | ||
| 			}
 | ||
| 		}
 | ||
| 		for exp >= 0 {
 | ||
| 			res[r_i] = `0`
 | ||
| 			r_i++
 | ||
| 			exp--
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		mut dot_p := true
 | ||
| 		for exp > 0 {
 | ||
| 			res[r_i] = `0`
 | ||
| 			r_i++
 | ||
| 			exp--
 | ||
| 			if dot_p {
 | ||
| 				res[r_i] = `.`
 | ||
| 				r_i++
 | ||
| 				dot_p = false
 | ||
| 			}
 | ||
| 		}
 | ||
| 		for b[i] != 0 {
 | ||
| 			res[r_i] = b[i]
 | ||
| 			r_i++
 | ||
| 			i++
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	// remove the dot form the numbers like 2.
 | ||
| 	if r_i > 1 && res[r_i - 1] == `.` {
 | ||
| 		r_i--
 | ||
| 	}
 | ||
| 
 | ||
| 	res[r_i] = 0
 | ||
| 	return unsafe { tos(res.data, r_i) }
 | ||
| }
 | ||
| 
 | ||
| // dec_digits return the number of decimal digit of an u64
 | ||
| pub fn dec_digits(n u64) int {
 | ||
| 	if n <= 9_999_999_999 { // 1-10
 | ||
| 		if n <= 99_999 { // 5
 | ||
| 			if n <= 99 { // 2
 | ||
| 				if n <= 9 { // 1
 | ||
| 					return 1
 | ||
| 				} else {
 | ||
| 					return 2
 | ||
| 				}
 | ||
| 			} else {
 | ||
| 				if n <= 999 { // 3
 | ||
| 					return 3
 | ||
| 				} else {
 | ||
| 					if n <= 9999 { // 4
 | ||
| 						return 4
 | ||
| 					} else {
 | ||
| 						return 5
 | ||
| 					}
 | ||
| 				}
 | ||
| 			}
 | ||
| 		} else {
 | ||
| 			if n <= 9_999_999 { // 7
 | ||
| 				if n <= 999_999 { // 6
 | ||
| 					return 6
 | ||
| 				} else {
 | ||
| 					return 7
 | ||
| 				}
 | ||
| 			} else {
 | ||
| 				if n <= 99_999_999 { // 8
 | ||
| 					return 8
 | ||
| 				} else {
 | ||
| 					if n <= 999_999_999 { // 9
 | ||
| 						return 9
 | ||
| 					}
 | ||
| 					return 10
 | ||
| 				}
 | ||
| 			}
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		if n <= 999_999_999_999_999 { // 5
 | ||
| 			if n <= 999_999_999_999 { // 2
 | ||
| 				if n <= 99_999_999_999 { // 1
 | ||
| 					return 11
 | ||
| 				} else {
 | ||
| 					return 12
 | ||
| 				}
 | ||
| 			} else {
 | ||
| 				if n <= 9_999_999_999_999 { // 3
 | ||
| 					return 13
 | ||
| 				} else {
 | ||
| 					if n <= 99_999_999_999_999 { // 4
 | ||
| 						return 14
 | ||
| 					} else {
 | ||
| 						return 15
 | ||
| 					}
 | ||
| 				}
 | ||
| 			}
 | ||
| 		} else {
 | ||
| 			if n <= 99_999_999_999_999_999 { // 7
 | ||
| 				if n <= 9_999_999_999_999_999 { // 6
 | ||
| 					return 16
 | ||
| 				} else {
 | ||
| 					return 17
 | ||
| 				}
 | ||
| 			} else {
 | ||
| 				if n <= 999_999_999_999_999_999 { // 8
 | ||
| 					return 18
 | ||
| 				} else {
 | ||
| 					if n <= 9_999_999_999_999_999_999 { // 9
 | ||
| 						return 19
 | ||
| 					}
 | ||
| 					return 20
 | ||
| 				}
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 |