1use alloc::string::{String, ToString};
20use alloc::vec::Vec;
21use core::fmt;
22use core::str::FromStr;
23
24use crate::bigint::BigUint;
25use crate::float::Float128;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum ParseFloat128Error {
30 Empty,
32 Unexpected {
34 found: char,
36 at: usize,
38 },
39 BadExponent,
41}
42
43impl fmt::Display for ParseFloat128Error {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 Self::Empty => write!(f, "a binary128 value needs at least one digit"),
47 Self::Unexpected { found, at } => {
48 write!(
49 f,
50 "`{found}` cannot appear at byte {at} of a binary128 value"
51 )
52 }
53 Self::BadExponent => write!(f, "the exponent is not an integer this crate can use"),
54 }
55 }
56}
57
58impl core::error::Error for ParseFloat128Error {}
59
60const DECIMAL_LIMIT: i64 = 6000;
64
65impl Float128 {
66 #[must_use]
72 pub fn to_exact_decimal(&self) -> String {
73 match self.exact_digits() {
74 None => non_finite(*self).to_string(),
75 Some((negative, digits, point)) => render(negative, &digits, point),
76 }
77 }
78
79 #[must_use]
87 pub fn to_shortest_decimal(&self) -> String {
88 let Some((negative, digits, point)) = self.exact_digits() else {
89 return non_finite(*self).to_string();
90 };
91 if digits.is_empty() {
92 return render(negative, &digits, point);
93 }
94 for length in 1..=Self::DIGITS_ROUND_TRIP {
95 if length >= digits.len() {
96 break;
97 }
98 let (rounded, rounded_point) = round_significant(&digits, point, length);
99 let text = render(negative, &rounded, rounded_point);
100 if Self::from_str(&text).is_ok_and(|back| back.to_bits() == self.to_bits()) {
101 return text;
102 }
103 }
104 render(negative, &digits, point)
105 }
106
107 fn exact_digits(&self) -> Option<(bool, Vec<u8>, i32)> {
112 let (negative, significand, exponent) = self.decompose()?;
113 if significand == 0 {
114 return Some((negative, Vec::new(), 0));
115 }
116 let mut value = BigUint::from_u128(significand);
117 let point;
118 if exponent >= 0 {
119 value.shl(exponent as usize);
120 let mut digits = value.to_decimal_digits();
121 point = decimal_point(digits.len(), 0);
122 trim_trailing_zeros(&mut digits);
123 return Some((negative, digits, point));
124 }
125 let scale = (-exponent) as usize;
128 value.mul_pow5(scale);
129 let mut digits = value.to_decimal_digits();
130 point = decimal_point(digits.len(), scale);
131 trim_trailing_zeros(&mut digits);
132 Some((negative, digits, point))
133 }
134}
135
136fn decimal_point(digits: usize, scale: usize) -> i32 {
145 let digits = i32::try_from(digits).unwrap_or(i32::MAX);
146 let scale = i32::try_from(scale).unwrap_or(i32::MAX);
147 digits.saturating_sub(scale)
148}
149
150fn trim_trailing_zeros(digits: &mut Vec<u8>) {
158 while digits.last() == Some(&0) {
159 digits.pop();
160 }
161}
162
163fn non_finite(value: Float128) -> &'static str {
165 if value.is_nan() {
166 "nan"
167 } else if value.is_sign_negative() {
168 "-inf"
169 } else {
170 "inf"
171 }
172}
173
174fn round_significant(digits: &[u8], point: i32, length: usize) -> (Vec<u8>, i32) {
179 let mut kept: Vec<u8> = digits[..length].to_vec();
180 let next = digits[length];
181 let rest_nonzero = digits[length + 1..].iter().any(|&digit| digit != 0);
182 let round_up = match next.cmp(&5) {
183 core::cmp::Ordering::Greater => true,
184 core::cmp::Ordering::Less => false,
185 core::cmp::Ordering::Equal => rest_nonzero || kept[length - 1] % 2 == 1,
186 };
187 if !round_up {
188 while kept.last() == Some(&0) {
189 kept.pop();
190 }
191 return (kept, point);
192 }
193 let mut index = length;
194 loop {
195 if index == 0 {
196 kept.insert(0, 1);
198 kept.truncate(length);
199 while kept.last() == Some(&0) {
200 kept.pop();
201 }
202 return (kept, point + 1);
203 }
204 index -= 1;
205 if kept[index] == 9 {
206 kept[index] = 0;
207 } else {
208 kept[index] += 1;
209 break;
210 }
211 }
212 while kept.last() == Some(&0) {
213 kept.pop();
214 }
215 (kept, point)
216}
217
218fn render(negative: bool, digits: &[u8], point: i32) -> String {
225 let mut out = String::new();
226 if negative {
227 out.push('-');
228 }
229 if digits.is_empty() {
230 out.push_str("0.0");
231 return out;
232 }
233 let length = decimal_point(digits.len(), 0);
234 if point > 0 && point <= 34 {
235 for (index, &digit) in digits.iter().enumerate() {
237 if decimal_point(index, 0) == point {
238 out.push('.');
239 }
240 out.push(char::from(b'0' + digit));
241 }
242 if length <= point {
243 for _ in length..point {
244 out.push('0');
245 }
246 out.push_str(".0");
247 }
248 return out;
249 }
250 if point <= 0 && point > -6 {
251 out.push_str("0.");
253 for _ in 0..-point {
254 out.push('0');
255 }
256 for &digit in digits {
257 out.push(char::from(b'0' + digit));
258 }
259 return out;
260 }
261 out.push(char::from(b'0' + digits[0]));
263 out.push('.');
264 if digits.len() == 1 {
265 out.push('0');
266 } else {
267 for &digit in &digits[1..] {
268 out.push(char::from(b'0' + digit));
269 }
270 }
271 out.push('e');
272 let exponent = point - 1;
273 if exponent >= 0 {
274 out.push('+');
275 }
276 out.push_str(&exponent.to_string());
277 out
278}
279
280impl fmt::Display for Float128 {
281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 f.pad(&self.to_shortest_decimal())
284 }
285}
286
287impl FromStr for Float128 {
288 type Err = ParseFloat128Error;
289
290 fn from_str(text: &str) -> Result<Self, Self::Err> {
296 parse(text)
297 }
298}
299
300fn parse(text: &str) -> Result<Float128, ParseFloat128Error> {
302 let trimmed = text.trim();
303 let (negative, body) = match trimmed.strip_prefix('-') {
304 Some(rest) => (true, rest),
305 None => (false, trimmed.strip_prefix('+').unwrap_or(trimmed)),
306 };
307 if body.is_empty() {
308 return Err(ParseFloat128Error::Empty);
309 }
310 if body.eq_ignore_ascii_case("inf") || body.eq_ignore_ascii_case("infinity") {
311 return Ok(if negative {
312 Float128::NEG_INFINITY
313 } else {
314 Float128::INFINITY
315 });
316 }
317 if body.eq_ignore_ascii_case("nan") {
318 let nan = Float128::NAN;
319 return Ok(if negative { nan.neg() } else { nan });
320 }
321
322 let (mantissa, exponent_text) = match body.find(['e', 'E']) {
324 Some(index) => (&body[..index], Some(&body[index + 1..])),
325 None => (body, None),
326 };
327 let mut exponent: i64 = match exponent_text {
328 None => 0,
329 Some(digits) => digits
330 .parse()
331 .map_err(|_| ParseFloat128Error::BadExponent)?,
332 };
333
334 let mut significand = BigUint::zero();
335 let mut seen_digit = false;
336 let mut seen_point = false;
337 let mut fraction_digits: i64 = 0;
338 for (offset, character) in mantissa.char_indices() {
339 match character {
340 '0'..='9' => {
341 seen_digit = true;
342 significand.mul_add_small(10, u32::from(character as u8 - b'0'));
343 if seen_point {
344 fraction_digits += 1;
345 }
346 }
347 '.' if !seen_point => seen_point = true,
348 other => {
352 return Err(ParseFloat128Error::Unexpected {
353 found: other,
354 at: offset,
355 });
356 }
357 }
358 }
359 if !seen_digit {
360 return Err(ParseFloat128Error::Empty);
361 }
362 exponent -= fraction_digits;
363
364 if significand.is_zero() {
365 return Ok(if negative {
366 Float128::NEG_ZERO
367 } else {
368 Float128::ZERO
369 });
370 }
371
372 let bits = significand.bit_length() as i64;
381 let digits_low = bits * 30103 / 100_000;
382 let digits_high = digits_low + 2;
383 if exponent + digits_low > DECIMAL_LIMIT {
384 return Ok(if negative {
385 Float128::NEG_INFINITY
386 } else {
387 Float128::INFINITY
388 });
389 }
390 if exponent + digits_high < -DECIMAL_LIMIT {
391 return Ok(if negative {
392 Float128::NEG_ZERO
393 } else {
394 Float128::ZERO
395 });
396 }
397
398 if exponent >= 0 {
399 let mut scaled = significand;
403 scaled.mul_pow10(exponent.unsigned_abs() as usize);
404 let (value, shift) = significand_with_sticky(scaled);
405 return Ok(Float128::from_parts_rounded(negative, value, shift).0);
406 }
407
408 let scale = exponent.unsigned_abs() as usize;
416 let wanted = 130 + scale * 10 / 3;
417 let have = significand.bit_length();
418 let shift = wanted.saturating_sub(have);
419 let mut numerator = significand;
420 numerator.shl(shift);
421 let sticky = divide_by_pow10(&mut numerator, scale);
422 let (mut value, extra) = significand_with_sticky(numerator);
423 if sticky {
424 value |= 1;
425 }
426 let exponent = extra - decimal_point(shift, 0);
427 Ok(Float128::from_parts_rounded(negative, value, exponent).0)
428}
429
430fn divide_by_pow10(value: &mut BigUint, power: usize) -> bool {
437 const CHUNK: u32 = 1_000_000_000;
438 const CHUNK_POWER: usize = 9;
439 let mut sticky = false;
440 let mut left = power;
441 while left >= CHUNK_POWER {
442 sticky |= value.div_rem_small(CHUNK) != 0;
443 left -= CHUNK_POWER;
444 }
445 if left != 0 {
446 let mut divisor = 1u32;
447 for _ in 0..left {
448 divisor *= 10;
449 }
450 sticky |= value.div_rem_small(divisor) != 0;
451 }
452 sticky
453}
454
455fn significand_with_sticky(value: BigUint) -> (u128, i32) {
460 let bits = value.bit_length();
461 if bits <= 127 {
462 return (value.to_u128().0, 0);
463 }
464 let drop = bits - 118;
467 let mut kept = value;
468 let lost = kept.shr(drop);
469 let (mut low, _) = kept.to_u128();
470 if lost {
471 low |= 1;
472 }
473 (low, decimal_point(drop, 0))
474}