lexical_write_float/
shared.rs
1use lexical_util::digit::{char_to_valid_digit_const, digit_to_char_const};
4use lexical_util::format::NumberFormat;
5use lexical_write_integer::write::WriteInteger;
6
7use crate::options::{Options, RoundMode};
8
9#[inline(always)]
11pub fn min_exact_digits(digit_count: usize, options: &Options) -> usize {
12 let mut exact_count: usize = digit_count;
13 if let Some(min_digits) = options.min_significant_digits() {
14 exact_count = min_digits.get().max(exact_count);
15 }
16 exact_count
17}
18
19#[cfg_attr(not(feature = "compact"), inline(always))]
24pub fn round_up(digits: &mut [u8], count: usize, radix: u32) -> (usize, bool) {
25 debug_assert!(count <= digits.len(), "rounding up requires digits.len() >= count");
26
27 let mut index = count;
28 let max_char = digit_to_char_const(radix - 1, radix);
29 while index != 0 {
30 let c = digits[index - 1];
31 if c < max_char {
32 let digit = char_to_valid_digit_const(c, radix);
33 let rounded = digit_to_char_const(digit + 1, radix);
34 digits[index - 1] = rounded;
36 return (index, false);
37 }
38 index -= 1;
41 }
42
43 digits[0] = b'1';
45
46 (1, true)
47}
48
49#[cfg_attr(not(feature = "compact"), inline(always))]
56#[allow(clippy::comparison_chain)] pub fn truncate_and_round_decimal(
58 digits: &mut [u8],
59 digit_count: usize,
60 options: &Options,
61) -> (usize, bool) {
62 debug_assert!(digit_count <= digits.len());
63
64 let max_digits = if let Some(digits) = options.max_significant_digits() {
65 digits.get()
66 } else {
67 return (digit_count, false);
68 };
69 if max_digits >= digit_count {
70 return (digit_count, false);
71 }
72
73 if options.round_mode() == RoundMode::Truncate {
75 return (max_digits, false);
77 }
78
79 let truncated = digits[max_digits];
87 let (digits, carried) = if truncated < b'5' {
88 (max_digits, false)
90 } else if truncated > b'5' {
91 round_up(digits, max_digits, 10)
93 } else {
94 let to_round = &digits[max_digits - 1..digit_count];
96 let is_odd = to_round[0] % 2 == 1;
97 let is_above = to_round[2..].iter().any(|&x| x != b'0');
98 if is_odd || is_above {
99 round_up(digits, max_digits, 10)
102 } else {
103 (max_digits, false)
104 }
105 };
106
107 (digits, carried)
108}
109
110#[cfg_attr(not(feature = "compact"), inline(always))]
112pub fn write_exponent_sign<const FORMAT: u128>(
113 bytes: &mut [u8],
114 cursor: &mut usize,
115 exp: i32,
116) -> u32 {
117 let format = NumberFormat::<{ FORMAT }> {};
118 if exp < 0 {
119 bytes[*cursor] = b'-';
120 *cursor += 1;
121 exp.wrapping_neg() as u32
122 } else if cfg!(feature = "format") && format.required_exponent_sign() {
123 bytes[*cursor] = b'+';
124 *cursor += 1;
125 exp as u32
126 } else {
127 exp as u32
128 }
129}
130
131#[cfg_attr(not(feature = "compact"), inline(always))]
133pub fn write_exponent<const FORMAT: u128>(
134 bytes: &mut [u8],
135 cursor: &mut usize,
136 exp: i32,
137 exponent_character: u8,
138) {
139 bytes[*cursor] = exponent_character;
140 *cursor += 1;
141 let positive_exp: u32 = write_exponent_sign::<FORMAT>(bytes, cursor, exp);
142 *cursor += positive_exp.write_exponent_signed::<FORMAT>(&mut bytes[*cursor..]);
143}
144
145macro_rules! write_float {
161 (
162 $float:ident,
163 $format:ident,
164 $sci_exp:ident,
165 $options:ident,
166 $write_scientific:ident,
167 $write_positive:ident,
168 $write_negative:ident,
169 $(generic => $generic:tt,)?
170 bytes => $bytes:ident,
171 args => $($args:expr,)*
172 ) => {{
173 use lexical_util::format::NumberFormat;
174
175 debug_assert!($float.is_sign_positive());
176
177 let format = NumberFormat::<{ $format }> {};
178 let min_exp = $options.negative_exponent_break().map_or(-5, |x| x.get());
179 let max_exp = $options.positive_exponent_break().map_or(9, |x| x.get());
180
181 let outside_break = $sci_exp < min_exp || $sci_exp > max_exp;
182 let require_exponent = format.required_exponent_notation() || outside_break;
183 if !format.no_exponent_notation() && require_exponent {
184 $write_scientific::<$($generic,)? FORMAT>($bytes, $($args,)*)
186 } else if $sci_exp < 0 {
187 $write_negative::<$($generic,)? FORMAT>($bytes, $($args,)*)
189 } else {
190 $write_positive::<$($generic,)? FORMAT>($bytes, $($args,)*)
192 }
193 }};
194}