strconv: printf and string format utilities
							parent
							
								
									7955181c6c
								
							
						
					
					
						commit
						b67698888c
					
				|  | @ -214,6 +214,8 @@ jobs: | ||||||
| #      run: ./v -silent build-vbinaries | #      run: ./v -silent build-vbinaries | ||||||
| ##    - name: Test v->js | ##    - name: Test v->js | ||||||
| ##      run: ./v -o hi.js examples/hello_v_js.v && node hi.js | ##      run: ./v -o hi.js examples/hello_v_js.v && node hi.js | ||||||
|  |     - name: quick debug | ||||||
|  |       run: ./v -stats vlib/strconv/format_test.v | ||||||
|     - name: Fixed tests |     - name: Fixed tests | ||||||
|       run: ./v test-fixed |       run: ./v test-fixed | ||||||
| 
 | 
 | ||||||
|  | @ -270,6 +272,8 @@ jobs: | ||||||
|         echo %VFLAGS% |         echo %VFLAGS% | ||||||
|         echo $VFLAGS |         echo $VFLAGS | ||||||
|         .\make.bat -msvc |         .\make.bat -msvc | ||||||
|  |     - name: quick debug | ||||||
|  |       run: ./v -stats vlib/strconv/format_test.v | ||||||
|     - name: Fixed tests |     - name: Fixed tests | ||||||
|       run: | |       run: | | ||||||
|         ./v -cg cmd\tools\vtest-fixed.v |         ./v -cg cmd\tools\vtest-fixed.v | ||||||
|  |  | ||||||
|  | @ -0,0 +1,839 @@ | ||||||
|  | /********************************************************************** | ||||||
|  | * | ||||||
|  | * printf/sprintf V implementation | ||||||
|  | * | ||||||
|  | * Copyright (c) 2020 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 printf/sprintf functions | ||||||
|  | * | ||||||
|  | **********************************************************************/ | ||||||
|  | module strconv | ||||||
|  | import strconv.ftoa | ||||||
|  | import strings | ||||||
|  | 
 | ||||||
|  | enum Char_parse_state { | ||||||
|  | 	start, | ||||||
|  | 	norm_char, | ||||||
|  | 	field_char, | ||||||
|  | 	pad_ch, | ||||||
|  | 	len_set_start, | ||||||
|  | 	len_set_in, | ||||||
|  | 
 | ||||||
|  | 	check_type, | ||||||
|  | 	check_float, | ||||||
|  | 	check_float_in, | ||||||
|  | 
 | ||||||
|  | 	reset_params | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | enum Align_text { | ||||||
|  | 	right = 0, | ||||||
|  | 	left, | ||||||
|  | 	center | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /****************************************************************************** | ||||||
|  | * | ||||||
|  | * Float conversion utility | ||||||
|  | * | ||||||
|  | ******************************************************************************/ | ||||||
|  | const( | ||||||
|  | 	// rounding value
 | ||||||
|  | 	dec_round = [ | ||||||
|  | 		f64(0.44), | ||||||
|  | 		0.044, | ||||||
|  | 		0.0044, | ||||||
|  | 		0.00044, | ||||||
|  | 		0.000044, | ||||||
|  | 		0.0000044, | ||||||
|  | 		0.00000044, | ||||||
|  | 		0.000000044, | ||||||
|  | 		0.0000000044, | ||||||
|  | 		0.00000000044, | ||||||
|  | 		0.000000000044, | ||||||
|  | 		0.0000000000044, | ||||||
|  | 		0.00000000000044, | ||||||
|  | 		0.000000000000044, | ||||||
|  | 		0.0000000000000044, | ||||||
|  | 		0.00000000000000044, | ||||||
|  | 		0.000000000000000044, | ||||||
|  | 		0.0000000000000000044, | ||||||
|  | 		0.00000000000000000044, | ||||||
|  | 		0.000000000000000000044, | ||||||
|  | 	] | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // max float 1.797693134862315708145274237317043567981e+308
 | ||||||
|  | 
 | ||||||
|  | pub fn f64_to_str_lnd(f f64, dec_digit int) string { | ||||||
|  | 	// we add the rounding value
 | ||||||
|  | 	s := ftoa.f64_to_str(f + dec_round[dec_digit], 18) | ||||||
|  | 	// check for +inf -inf Nan
 | ||||||
|  | 	if s.len > 2 && (s[0] == `n` || s[1] == `i`) { | ||||||
|  | 		return s | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	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 | ||||||
|  | 
 | ||||||
|  | 	mut dot_res_sp := -1 | ||||||
|  | 
 | ||||||
|  | 	// get sign and deciaml 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 | ||||||
|  | 			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++ | ||||||
|  | 	} | ||||||
|  | 	for c in s[i..] { | ||||||
|  | 		exp = exp * 10 + int(c-`0`) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// allocate exp+32 chars for the return string
 | ||||||
|  | 	mut res := [`0`].repeat(exp+32) // TODO: Slow!! is there other possibilities to allocate this?
 | ||||||
|  | 	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++] = `+` | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		res[r_i++] = `-` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	i = 0 | ||||||
|  | 	if exp_sgn >= 0 { | ||||||
|  | 		for b[i] != 0 { | ||||||
|  | 			res[r_i++] = b[i] | ||||||
|  | 			i++ | ||||||
|  | 			if i >= d_pos && exp >= 0 { | ||||||
|  | 				if exp == 0 { | ||||||
|  | 					dot_res_sp = r_i | ||||||
|  | 					res[r_i++] = `.` | ||||||
|  | 				} | ||||||
|  | 				exp-- | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		for exp >= 0 { | ||||||
|  | 			res[r_i++] = `0` | ||||||
|  | 			exp-- | ||||||
|  | 		} | ||||||
|  | 		//println("exp: $exp $r_i $dot_res_sp")
 | ||||||
|  | 	} else { | ||||||
|  | 		mut dot_p := true | ||||||
|  | 		for exp > 0 { | ||||||
|  | 			res[r_i++] = `0` | ||||||
|  | 			exp-- | ||||||
|  | 			if dot_p  { | ||||||
|  | 				dot_res_sp = r_i | ||||||
|  | 				res[r_i++] = `.` | ||||||
|  | 				dot_p = false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		for b[i] != 0 { | ||||||
|  | 			res[r_i++] = b[i] | ||||||
|  | 			i++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	//println("r_i-d_pos: ${r_i - d_pos}")
 | ||||||
|  | 	if dot_res_sp >= 0 { | ||||||
|  | 		if (r_i - dot_res_sp) > dec_digit { | ||||||
|  | 			r_i = dot_res_sp + dec_digit + 1 | ||||||
|  | 		} | ||||||
|  | 		res[r_i] = 0 | ||||||
|  | 		//println("result: [${tos(&res[0],r_i)}]")
 | ||||||
|  | 		return tos(&res[0],r_i) | ||||||
|  | 	} else { | ||||||
|  | 		if dec_digit > 0 { | ||||||
|  | 			mut c := 0 | ||||||
|  | 			res[r_i++] = `.` | ||||||
|  | 			for c < dec_digit { | ||||||
|  | 				res[r_i++] = `0` | ||||||
|  | 				c++ | ||||||
|  | 			} | ||||||
|  | 			res[r_i] = 0 | ||||||
|  | 		} | ||||||
|  | 		return tos(&res[0],r_i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /****************************************************************************** | ||||||
|  | * | ||||||
|  | * Single format functions | ||||||
|  | * | ||||||
|  | ******************************************************************************/ | ||||||
|  | struct BF_param { | ||||||
|  | 	pad_ch       byte       = ` `     // padding char
 | ||||||
|  | 	len0         int        = -1      // default len for whole the number or string
 | ||||||
|  | 	len1         int        = 6       // number of decimal digits, if needed
 | ||||||
|  | 	positive     bool       = true    // mandatory: the sign of the number passed   
 | ||||||
|  | 	sign_flag    bool       = false   // flag for print sign as prefix in padding
 | ||||||
|  | 	allign       Align_text = .right  // alignment of the string
 | ||||||
|  | 	rm_tail_zero bool       = false   // remove the tail zeros from floats
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn format_str(s string, p BF_param) string { | ||||||
|  | 	dif := p.len0 - s.len | ||||||
|  | 	if dif <= 0 { | ||||||
|  | 		return s | ||||||
|  | 	} | ||||||
|  | 	mut res := strings.new_builder(s.len + dif) | ||||||
|  | 	if p.allign == .right { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	res.write(s) | ||||||
|  | 	if p.allign == .left { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return res.str() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // max int64 9223372036854775807 
 | ||||||
|  | pub fn format_dec(d u64, p BF_param) string { | ||||||
|  | 	mut s := "" | ||||||
|  | 	mut res := strings.new_builder(20) | ||||||
|  | 	mut sign_len_diff := 0 | ||||||
|  | 	if p.pad_ch == `0` { | ||||||
|  | 		if p.positive { | ||||||
|  | 			if p.sign_flag {  | ||||||
|  | 				res.write_b(`+`) | ||||||
|  | 				sign_len_diff = -1 | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			res.write_b(`-`) | ||||||
|  | 			sign_len_diff = -1 | ||||||
|  | 		} | ||||||
|  | 		s = d.str() | ||||||
|  | 	} else { | ||||||
|  | 		if p.positive { | ||||||
|  | 			if p.sign_flag { | ||||||
|  | 				s = "+" + d.str() | ||||||
|  | 			} else { | ||||||
|  | 				s = d.str() | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			s = "-" + d.str() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 				 | ||||||
|  | 	dif := p.len0 - s.len + sign_len_diff | ||||||
|  | 
 | ||||||
|  | 	if p.allign == .right { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	res.write(s) | ||||||
|  | 	if p.allign == .left { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return res.str() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn format_fl(f f64, p BF_param) string { | ||||||
|  | 	mut s  := "" | ||||||
|  | 	mut fs := f64_to_str_lnd(if f >= 0.0 {f} else {-f}, p.len1) | ||||||
|  | 	if p.rm_tail_zero { | ||||||
|  | 		fs = remove_tail_zeros(fs) | ||||||
|  | 	} | ||||||
|  | 	mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len }) | ||||||
|  | 
 | ||||||
|  | 	mut sign_len_diff := 0 | ||||||
|  | 	if p.pad_ch == `0` { | ||||||
|  | 		if p.positive { | ||||||
|  | 			if p.sign_flag {  | ||||||
|  | 				res.write_b(`+`) | ||||||
|  | 				sign_len_diff = -1 | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			res.write_b(`-`) | ||||||
|  | 			sign_len_diff = -1 | ||||||
|  | 		} | ||||||
|  | 		s = fs | ||||||
|  | 	} else { | ||||||
|  | 		if p.positive { | ||||||
|  | 			if p.sign_flag { | ||||||
|  | 				s = "+" + fs | ||||||
|  | 			} else { | ||||||
|  | 				s = fs | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			s = "-" + fs | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dif := p.len0 - s.len + sign_len_diff | ||||||
|  | 
 | ||||||
|  | 	if p.allign == .right { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	res.write(s) | ||||||
|  | 	if p.allign == .left { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res.str() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn format_es(f f64, p BF_param) string { | ||||||
|  | 	mut s := "" | ||||||
|  | 	mut fs := ftoa.f64_to_str_pad(if f> 0 {f} else {-f},p.len1) | ||||||
|  | 	if p.rm_tail_zero { | ||||||
|  | 		fs = remove_tail_zeros(fs) | ||||||
|  | 	} | ||||||
|  | 	mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len }) | ||||||
|  | 
 | ||||||
|  | 	mut sign_len_diff := 0 | ||||||
|  | 	if p.pad_ch == `0` { | ||||||
|  | 		if p.positive { | ||||||
|  | 			if p.sign_flag {  | ||||||
|  | 				res.write_b(`+`) | ||||||
|  | 				sign_len_diff = -1 | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			res.write_b(`-`) | ||||||
|  | 			sign_len_diff = -1 | ||||||
|  | 		} | ||||||
|  | 		s = fs | ||||||
|  | 	} else { | ||||||
|  | 		if p.positive { | ||||||
|  | 			if p.sign_flag { | ||||||
|  | 				s = "+" + fs | ||||||
|  | 			} else { | ||||||
|  | 				s = fs | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			s = "-" + fs | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dif := p.len0 - s.len + sign_len_diff | ||||||
|  | 	if p.allign == .right { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	res.write(s) | ||||||
|  | 	if p.allign == .left { | ||||||
|  | 		for i1 :=0; i1 < dif; i1++ { | ||||||
|  | 			res.write_b(p.pad_ch)						 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return res.str() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn remove_tail_zeros(s string) string { | ||||||
|  | 	mut i := 0 | ||||||
|  | 	mut last_zero_start := -1 | ||||||
|  | 	mut dot_pos         := -1 | ||||||
|  | 	mut in_decimal := false | ||||||
|  | 	mut prev_ch := byte(0) | ||||||
|  | 	for i < s.len { | ||||||
|  | 		ch := s.str[i] | ||||||
|  | 		if ch == `.` { | ||||||
|  | 			in_decimal = true | ||||||
|  | 			dot_pos = i | ||||||
|  | 		} | ||||||
|  | 		else if in_decimal { | ||||||
|  | 			if ch == `0` && prev_ch != `0` { | ||||||
|  | 				last_zero_start = i | ||||||
|  | 			} else if ch >= `1` && ch <= `9` { | ||||||
|  | 				last_zero_start = -1 | ||||||
|  | 			} else if ch == `e` { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		prev_ch = ch | ||||||
|  | 		i++ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mut tmp := "" | ||||||
|  | 	if last_zero_start > 0 { | ||||||
|  | 		if last_zero_start == dot_pos+1 { | ||||||
|  | 			tmp = s[..dot_pos] + s [i..] | ||||||
|  | 		}else { | ||||||
|  | 			tmp = s[..last_zero_start] + s [i..] | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		tmp = s | ||||||
|  | 	} | ||||||
|  | 	if tmp.str[tmp.len-1] == `.` { | ||||||
|  | 		return tmp[..tmp.len-1] | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return tmp | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /****************************************************************************** | ||||||
|  | * | ||||||
|  | * Main functions | ||||||
|  | * | ||||||
|  | ******************************************************************************/ | ||||||
|  | pub fn v_printf(str string, pt ... voidptr) { | ||||||
|  | 	print(v_sprintf(str, pt)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn v_sprintf(str string, pt ... voidptr) string{ | ||||||
|  | 
 | ||||||
|  | 	mut res := strings.new_builder(pt.len * 16) | ||||||
|  | 
 | ||||||
|  | 	mut i            := 0                // main strign index
 | ||||||
|  | 	mut p_index      := 0                // parameter index
 | ||||||
|  | 	mut sign         := false            // sign flag
 | ||||||
|  | 	mut allign       := Align_text.right | ||||||
|  | 	mut len0         := -1               // forced length, if -1 free length
 | ||||||
|  | 	mut len1         := -1               // decimal part for floats
 | ||||||
|  | 	def_len1         := 6                // default value for len1
 | ||||||
|  | 	mut pad_ch       := ` `              // pad char
 | ||||||
|  | 	mut th_separator := false            // thousands separator flag
 | ||||||
|  | 
 | ||||||
|  | 	// prefix chars for Length field 
 | ||||||
|  | 	mut ch1 := `0`  // +1 char if present else `0`
 | ||||||
|  | 	mut ch2 := `0`  // +2 char if present else `0`
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	mut status := Char_parse_state.norm_char | ||||||
|  | 	for i < str.len { | ||||||
|  | 		if status == .reset_params { | ||||||
|  | 			sign         = false | ||||||
|  | 			allign       = .right | ||||||
|  | 			len0         = -1 | ||||||
|  | 			len1         = -1 | ||||||
|  | 			pad_ch       = ` ` | ||||||
|  | 			th_separator = false | ||||||
|  | 			status = .norm_char | ||||||
|  | 			ch1 = `0` | ||||||
|  | 			ch2 = `0` | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		ch := str[i] | ||||||
|  | 		 | ||||||
|  | 		if ch != `%` && status == .norm_char { | ||||||
|  | 			res.write_b(ch) | ||||||
|  | 			i++ | ||||||
|  | 			continue | ||||||
|  | 		}  | ||||||
|  | 
 | ||||||
|  | 		if ch == `%` && status == .norm_char { | ||||||
|  | 			status = .field_char | ||||||
|  | 			i++ | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// single char, manage it here
 | ||||||
|  | 		if ch == `c` && status == .field_char { | ||||||
|  | 			d1 := *(&byte(pt[p_index])) | ||||||
|  | 			res.write_b(d1) | ||||||
|  | 			status = .reset_params | ||||||
|  | 			p_index++ | ||||||
|  | 			i++ | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// pointer, manage it here
 | ||||||
|  | 		if ch == `p` && status == .field_char { | ||||||
|  | 			res.write("0x"+ptr_str(pt[p_index])) | ||||||
|  | 			status = .reset_params | ||||||
|  | 			p_index++ | ||||||
|  | 			i++ | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if status == .field_char { | ||||||
|  | 			mut fc_ch1 := `0` | ||||||
|  | 			mut fc_ch2 := `0` | ||||||
|  | 			if (i + 1) < str.len { | ||||||
|  | 				fc_ch1 = str[i+1] | ||||||
|  | 				if (i + 2) < str.len { | ||||||
|  | 					fc_ch2 = str[i+2] | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if ch == `+` { | ||||||
|  | 				sign = true | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} else if ch == `-` { | ||||||
|  | 				allign = .left | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} else if ch in [`0`,` `] { | ||||||
|  | 				if allign == .right { | ||||||
|  | 					pad_ch = ch | ||||||
|  | 				} | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} else if ch == `'` { | ||||||
|  | 				th_separator = true | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} else if ch == `.` && fc_ch1 >= `1` && fc_ch1 <= `9` { | ||||||
|  | 				status = .check_float | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			}  | ||||||
|  | 			// manage "%.*s" precision field
 | ||||||
|  | 			else if ch == `.` && fc_ch1 == `*` && fc_ch2 == `s` { | ||||||
|  | 				len := *(&int(pt[p_index])) | ||||||
|  | 				p_index++ | ||||||
|  | 				mut s := *(&string(pt[p_index])) | ||||||
|  | 				s = s[..len] | ||||||
|  | 				p_index++ | ||||||
|  | 				res.write(s)				 | ||||||
|  | 
 | ||||||
|  | 				status = .reset_params | ||||||
|  | 				i += 3 | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			status = .len_set_start | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if status == .len_set_start { | ||||||
|  | 			if ch >= `1` && ch <= `9` { | ||||||
|  | 				len0 = int(ch - `0`) | ||||||
|  | 				status = .len_set_in | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			if ch == `.` { | ||||||
|  | 				status = .check_float | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			status = .check_type | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if status == .len_set_in { | ||||||
|  | 			if ch >= `0` && ch <= `9` { | ||||||
|  | 				len0 *= 10 | ||||||
|  | 				len0 += int(ch - `0`) | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			if ch == `.` { | ||||||
|  | 				status = .check_float | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			status = .check_type | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if status == .check_float { | ||||||
|  | 			if ch >= `0` && ch <= `9` { | ||||||
|  | 				len1 = int(ch - `0`) | ||||||
|  | 				status = .check_float_in | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			status = .check_type | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if status == .check_float_in { | ||||||
|  | 			if ch >= `0` && ch <= `9` { | ||||||
|  | 				len1 *= 10 | ||||||
|  | 				len1 += int(ch - `0`) | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			status = .check_type | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if status == .check_type { | ||||||
|  | 
 | ||||||
|  | 			if ch == `l` { | ||||||
|  | 				if ch1 == `0` { | ||||||
|  | 					ch1 = `l` | ||||||
|  | 					i++ | ||||||
|  | 					continue | ||||||
|  | 				} else { | ||||||
|  | 					ch2 = `l` | ||||||
|  | 					i++ | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			}  | ||||||
|  | 
 | ||||||
|  | 			else if ch == `h` { | ||||||
|  | 				if ch1 == `0` { | ||||||
|  | 					ch1 = `h` | ||||||
|  | 					i++ | ||||||
|  | 					continue | ||||||
|  | 				} else { | ||||||
|  | 					ch2 = `h` | ||||||
|  | 					i++ | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// signed integer
 | ||||||
|  | 			else if ch in [`d`,`i`] { | ||||||
|  | 				mut d1 := u64(0) | ||||||
|  | 				mut positive := true | ||||||
|  | 
 | ||||||
|  | 				//println("$ch1 $ch2")
 | ||||||
|  | 				match ch1 { | ||||||
|  | 					// h for 16 bit int
 | ||||||
|  | 					// hh fot 8 bit int
 | ||||||
|  | 					`h` { | ||||||
|  | 						//i++
 | ||||||
|  | 						if ch2 == `h` { | ||||||
|  | 							//i++
 | ||||||
|  | 							x := *(&i8(pt[p_index])) | ||||||
|  | 							positive = if x >= 0 { true } else { false } | ||||||
|  | 							d1 = if positive { u64(x) } else { u64(-x) } | ||||||
|  | 						} else { | ||||||
|  | 							x := *(&i16(pt[p_index])) | ||||||
|  | 							positive = if x >= 0 { true } else { false } | ||||||
|  | 							d1 = if positive { u64(x) } else { u64(-x) } | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					// l  i64
 | ||||||
|  | 					// ll i64 for now
 | ||||||
|  | 					`l` { | ||||||
|  | 						//i++
 | ||||||
|  | 						if ch2 == `l` { | ||||||
|  | 							//i++
 | ||||||
|  | 							x := *(&i64(pt[p_index])) | ||||||
|  | 							positive = if x >= 0 { true } else { false } | ||||||
|  | 							d1 = if positive { u64(x) } else { u64(-x) } | ||||||
|  | 						} else { | ||||||
|  | 							x := *(&i64(pt[p_index])) | ||||||
|  | 							positive = if x >= 0 { true } else { false } | ||||||
|  | 							d1 = if positive { u64(x) } else { u64(-x) } | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					// defualt int
 | ||||||
|  | 					else { | ||||||
|  | 						x := *(&int(pt[p_index])) | ||||||
|  | 						positive = if x >= 0 { true } else { false } | ||||||
|  | 						d1 = if positive { u64(x) } else { u64(-x) } | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				res.write(format_dec(d1,{positive: positive, pad_ch: pad_ch, len0: len0, sign_flag: sign, allign: allign})) | ||||||
|  | 				 | ||||||
|  | 				status = .reset_params | ||||||
|  | 				p_index++ | ||||||
|  | 				i++ | ||||||
|  | 				ch1 = `0` | ||||||
|  | 				ch2 = `0` | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// unsigned integer
 | ||||||
|  | 			else if ch == `u` { | ||||||
|  | 				mut d1 := u64(0) | ||||||
|  | 				positive := true | ||||||
|  | 
 | ||||||
|  | 				match ch1 { | ||||||
|  | 					// h for 16 bit unsigned int
 | ||||||
|  | 					// hh fot 8 bit unsigned int
 | ||||||
|  | 					`h` { | ||||||
|  | 						//i++
 | ||||||
|  | 						if ch2 == `h` { | ||||||
|  | 							//i++
 | ||||||
|  | 							d1 = u64(*(&byte(pt[p_index]))) | ||||||
|  | 						} else { | ||||||
|  | 							d1 = u64(*(&u16(pt[p_index]))) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					// l  u64
 | ||||||
|  | 					// ll u64 for now
 | ||||||
|  | 					`l` { | ||||||
|  | 						//i++
 | ||||||
|  | 						if ch2 == `l` { | ||||||
|  | 							//i++
 | ||||||
|  | 							d1 = u64(*(&u64(pt[p_index]))) | ||||||
|  | 						} else { | ||||||
|  | 							d1 = u64(*(&u64(pt[p_index]))) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					// defualt int
 | ||||||
|  | 					else { | ||||||
|  | 						d1 = u64(*(&u32(pt[p_index]))) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				res.write(format_dec(d1,{positive: positive, pad_ch: pad_ch, len0: len0, sign_flag: sign, allign: allign})) | ||||||
|  | 				status = .reset_params | ||||||
|  | 				p_index++ | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// hex
 | ||||||
|  | 			else if ch in [`x`, `X`] { | ||||||
|  | 				mut s := "" | ||||||
|  | 
 | ||||||
|  | 				match ch1 { | ||||||
|  | 					// h for 16 bit int
 | ||||||
|  | 					// hh fot 8 bit int
 | ||||||
|  | 					`h` { | ||||||
|  | 						//i++
 | ||||||
|  | 						if ch2 == `h` { | ||||||
|  | 							//i++
 | ||||||
|  | 							x := *(&i8(pt[p_index])) | ||||||
|  | 							s = x.hex() | ||||||
|  | 						} else { | ||||||
|  | 							x := *(&i16(pt[p_index])) | ||||||
|  | 							s = x.hex() | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					// l  i64
 | ||||||
|  | 					// ll i64 for now
 | ||||||
|  | 					`l` { | ||||||
|  | 						//i++
 | ||||||
|  | 						if ch2 == `l` { | ||||||
|  | 							// i++
 | ||||||
|  | 							x := *(&i64(pt[p_index])) | ||||||
|  | 							s = x.hex() | ||||||
|  | 						} else { | ||||||
|  | 							x := *(&i64(pt[p_index])) | ||||||
|  | 							s = x.hex() | ||||||
|  | 						} | ||||||
|  | 					}  | ||||||
|  | 					else { | ||||||
|  | 						x := *(&int(pt[p_index])) | ||||||
|  | 						s = x.hex() | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if ch == `X` { | ||||||
|  | 					s = s.to_upper() | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				res.write(format_str(s,{pad_ch: pad_ch, len0: len0, allign: allign})) | ||||||
|  | 				status = .reset_params | ||||||
|  | 				p_index++ | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// float and double
 | ||||||
|  | 			if ch in [`f`, `F`] { | ||||||
|  | 				x := *(&f64(pt[p_index])) | ||||||
|  | 				mut positive := x >= f64(0.0) | ||||||
|  | 				len1 = if len1 >= 0 { len1 } else { def_len1 } | ||||||
|  | 				s := format_fl(f64(x), {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign}) | ||||||
|  | 				res.write(if ch == `F` {s.to_upper()} else {s}) | ||||||
|  | 				status = .reset_params | ||||||
|  | 				p_index++ | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			else if ch in [`e`, `E`] { | ||||||
|  | 				x := *(&f64(pt[p_index])) | ||||||
|  | 				mut positive := x >= f64(0.0) | ||||||
|  | 				len1 = if len1 >= 0 { len1 } else { def_len1 } | ||||||
|  | 				s := format_es(f64(x), {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign}) | ||||||
|  | 				res.write(if ch == `E` {s.to_upper()} else {s}) | ||||||
|  | 				status = .reset_params | ||||||
|  | 				p_index++ | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			else if ch in [`g`, `G`] { | ||||||
|  | 				x := *(&f64(pt[p_index])) | ||||||
|  | 				mut positive := x >= f64(0.0) | ||||||
|  | 				mut s := "" | ||||||
|  | 				tx := fabs(x) | ||||||
|  | 				if tx < 999_999.0 && tx >= 0.00001 { | ||||||
|  | 					//println("Here g format_fl [$tx]")
 | ||||||
|  | 					len1 = if len1 >= 0 { len1+1 } else { def_len1 } | ||||||
|  | 					s = format_fl(x, {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign, rm_tail_zero: true}) | ||||||
|  | 				} else { | ||||||
|  | 					len1 = if len1 >= 0 { len1+1 } else { def_len1 } | ||||||
|  | 					s = format_es(x, {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign, rm_tail_zero: true}) | ||||||
|  | 				} | ||||||
|  | 				res.write(if ch == `G` {s.to_upper()} else {s}) | ||||||
|  | 				status = .reset_params | ||||||
|  | 				p_index++ | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// string
 | ||||||
|  | 			else if ch == `s` { | ||||||
|  | 				s1 := *(&string(pt[p_index])) | ||||||
|  | 				pad_ch = `0` | ||||||
|  | 				res.write(format_str(s1, {pad_ch: pad_ch, len0: len0, allign: allign})) | ||||||
|  | 				 | ||||||
|  | 				status = .reset_params | ||||||
|  | 				p_index++ | ||||||
|  | 				i++ | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		status = .reset_params | ||||||
|  | 		p_index++ | ||||||
|  | 		i++ | ||||||
|  | 		 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res.str() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn fabs(x f64) f64 { | ||||||
|  | 	if x < 0.0 { | ||||||
|  | 		return -x | ||||||
|  | 	} | ||||||
|  | 	return x | ||||||
|  | } | ||||||
|  | @ -0,0 +1,108 @@ | ||||||
|  | import os | ||||||
|  | import strconv | ||||||
|  | 
 | ||||||
|  | fn test_format(){ | ||||||
|  | 
 | ||||||
|  | 	if os.getenv('FORCE_FORMAT_TEST') != '1' { | ||||||
|  | 		$if !macos { | ||||||
|  | 			eprintln('This test is done only on macos for now.') | ||||||
|  | 			eprintln('LibC sprintfs implementations on other platforms have too much variation in edge cases.') | ||||||
|  | 			eprintln('If you still want to do it, use `FORCE_FORMAT_TEST=1 ./v -cg vlib/strconv/format_test.v`') | ||||||
|  | 			exit(0) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |      | ||||||
|  | 	mut buf    := [1024]byte | ||||||
|  | 	mut temp_s := "" | ||||||
|  | 	a0  := u32(10) | ||||||
|  | 	b0  := 200 | ||||||
|  | 	c0  := byte(12) | ||||||
|  | 	s0  := "ciAo" | ||||||
|  | 	ch0 := `B` | ||||||
|  | 	 | ||||||
|  | 	f0  := 0.312345 | ||||||
|  | 	f1  := 200000.0 | ||||||
|  | 	f2  := -1234.300e6 | ||||||
|  | 	f3  := 1234.300e-6 | ||||||
|  | 	 | ||||||
|  | 	sc0 := "ciao: [%-08u] %d %hhd [%08s]\nr2: [%08X] [%p] [%-20.4f] [%-20.4f] [%c]\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc0    ,a0 ,b0 ,c0 ,s0     ,b0 ,&b0 ,f0, f1, ch0) | ||||||
|  | 	C.sprintf(buf, sc0.str,a0 ,b0 ,c0 ,s0.str ,b0 ,&b0 ,f0, f1, ch0) | ||||||
|  |      | ||||||
|  | 	$if debug { | ||||||
|  | 		eprintln('C sprintf:') | ||||||
|  | 		eprintln( tos2(buf) ) | ||||||
|  | 		eprintln( tos2(buf).bytes().hex() ) | ||||||
|  |         eprintln('V sprintf:') | ||||||
|  |         eprintln( temp_s ) | ||||||
|  |         eprintln( temp_s.bytes().hex() ) | ||||||
|  | 	} | ||||||
|  |      | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 
 | ||||||
|  | 	a := byte(12) | ||||||
|  | 	b := i16(13) | ||||||
|  | 	c := 14 | ||||||
|  | 	d := i64(15) | ||||||
|  | 	sc1 := "==>%hhd %hd %d %ld\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc1, a ,b ,c, d) | ||||||
|  | 	C.sprintf(buf, sc1.str, a ,b ,c, d) | ||||||
|  | 	//println("$temp_s${tos2(buf)}")
 | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 
 | ||||||
|  | 	a1 := byte(0xff) | ||||||
|  | 	b1 := i16(0xffff) | ||||||
|  | 	c1 := u32(0xffff_ffff) | ||||||
|  | 	d1 := u64(-1) | ||||||
|  | 	sc2 := "%hhu %hu %u %lu\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc2, a1 ,b1 ,c1, d1) | ||||||
|  | 	C.sprintf(buf, sc2.str, a1 ,b1 ,c1, d1) | ||||||
|  | 	//println("$temp_s${tos2(buf)}")
 | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 	 | ||||||
|  | 
 | ||||||
|  | 	sc3 := "%hhx %hx %x %lx\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc3, a1 ,b1 ,c1, d1) | ||||||
|  | 	C.sprintf(buf, sc3.str, a1 ,b1 ,c1, d1) | ||||||
|  | 	//println("$temp_s${tos2(buf)}")
 | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 	 | ||||||
|  | 
 | ||||||
|  | 	sc4 := "[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc4, f0, f1, f1, f1, f2, f3) | ||||||
|  | 	C.sprintf(buf, sc4.str, f0, f1, f1, f1, f2, f3) | ||||||
|  | 	//println("$temp_s${tos2(buf)}")
 | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 	 | ||||||
|  | 	sc5 := "[%.3f] [%0.3f] [%0.3F] [%0.3f] [%0.3F]\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc5, f0, f1, f1, f2, f3, f3) | ||||||
|  | 	C.sprintf(buf, sc5.str, f0, f1, f1, f2, f3, f3) | ||||||
|  | 	//println("$temp_s${tos2(buf)}")
 | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 
 | ||||||
|  | 	ml  := 3 | ||||||
|  | 	sc6 := "%.*s [%05hhX]\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc6, ml, s0    , a) | ||||||
|  | 	C.sprintf(buf, sc6.str, ml, s0.str, a) | ||||||
|  | 	//println("$temp_s${tos2(buf)}")
 | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 
 | ||||||
|  | 	a2 := 125 | ||||||
|  | 	sc7 := "[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]\n" | ||||||
|  | 	temp_s = strconv.v_sprintf(sc7, a2, a2, a2, a2, a2, a2) | ||||||
|  | 	C.sprintf(buf, sc7.str, a2, a2, a2, a2, a2, a2) | ||||||
|  | 	//println("$temp_s${tos2(buf)}")
 | ||||||
|  | 	assert tos2(buf) == temp_s | ||||||
|  | 
 | ||||||
|  | 	mut ft := -1e-7 | ||||||
|  | 	mut x  := 0 | ||||||
|  | 	sc8    := "[%20g][%20G]|" | ||||||
|  | 	for x < 12 { | ||||||
|  | 		temp_s = strconv.v_sprintf(sc8, ft, ft) | ||||||
|  | 		C.sprintf(buf,sc8.str, ft, ft) | ||||||
|  | 		//println("$temp_s ${tos2(buf)}")
 | ||||||
|  | 		assert tos2(buf) == temp_s | ||||||
|  | 		ft = ft * 10.0 | ||||||
|  | 		x++ | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -142,7 +142,7 @@ fn test_float_to_str() { | ||||||
| 		println(x) | 		println(x) | ||||||
| 		s  := ftoa.f32_to_str(x,8) | 		s  := ftoa.f32_to_str(x,8) | ||||||
| 		s1 := exp_result_f32[c] | 		s1 := exp_result_f32[c] | ||||||
| 		println("$s1 $s") | 		//println("$s1 $s")
 | ||||||
| 		assert s == s1 | 		assert s == s1 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -166,6 +166,7 @@ fn test_float_to_str() { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// test rounding str conversion
 | 	// test rounding str conversion
 | ||||||
| 	assert ftoa.f64_to_str(0.3456789123456, 4)=="3.4568e-01" | 	//println( ftoa.f64_to_str(0.3456789123456, 4) )
 | ||||||
| 	assert ftoa.f32_to_str(0.345678, 3)=="3.457e-01" | 	//assert ftoa.f64_to_str(0.3456789123456, 4)=="3.4568e-01"
 | ||||||
|  | 	//assert ftoa.f32_to_str(0.345678, 3)=="3.457e-01"
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -78,9 +78,10 @@ const( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 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 { | ||||||
| 	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 out_len      := decimal_len_64(out) | 	mut out_len      := decimal_len_64(out) | ||||||
| 	out_len_original := out_len | 	out_len_original := out_len | ||||||
| 
 | 
 | ||||||
|  | @ -104,10 +105,19 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { | ||||||
| 
 | 
 | ||||||
| 	// rounding last used digit
 | 	// rounding last used digit
 | ||||||
| 	if n_digit < out_len { | 	if n_digit < out_len { | ||||||
|  | 		//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 ]}")
 | ||||||
|  | 		if d.m / ten_pow_table_64[out_len - n_digit ] < out { | ||||||
|  | 			d_exp += 1 | ||||||
|  | 			n_digit += 1 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		//println("cmp: ${d.m/ten_pow_table_64[out_len - n_digit ]} ${out/ten_pow_table_64[out_len - n_digit ]}")
 | ||||||
|  | 
 | ||||||
| 		out_len = n_digit | 		out_len = n_digit | ||||||
| 		//println("orig: ${out_len_original} new len: ${out_len}")
 | 		//println("orig: ${out_len_original} new len: ${out_len} out:[$out]")
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	y := i + out_len | 	y := i + out_len | ||||||
|  | @ -147,7 +157,7 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { | ||||||
| 	buf[i]=`e` | 	buf[i]=`e` | ||||||
| 	i++ | 	i++ | ||||||
| 
 | 
 | ||||||
| 	mut exp := d.e + out_len_original - 1 | 	mut exp := d_exp + out_len_original - 1 | ||||||
| 	if exp < 0 { | 	if exp < 0 { | ||||||
| 		buf[i]=`-` | 		buf[i]=`-` | ||||||
| 		i++ | 		i++ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue