malachite_nz/integer/conversion/string/from_sci_string.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::integer::Integer;
10use crate::natural::conversion::string::from_sci_string::{
11 FromSciStringHelper, from_sci_string_with_options_helper,
12};
13use malachite_base::num::basic::traits::One;
14use malachite_base::num::conversion::string::options::FromSciStringOptions;
15use malachite_base::num::conversion::traits::{FromSciString, FromStringBase};
16
17impl FromSciStringHelper for Integer {
18 fn parse_int(mut cs: &[u8], base: u8) -> Option<Self> {
19 if let Some(b'+') = cs.first() {
20 cs = &cs[1..];
21 // If the string begins with a '+', the second character cannot be '+' or '-'
22 match cs {
23 [] | [b'+' | b'-', ..] => return None,
24 _ => {}
25 }
26 }
27 Self::from_string_base(base, core::str::from_utf8(cs).ok()?)
28 }
29
30 fn up_1(self, neg: bool) -> Option<Self> {
31 Some(if neg {
32 self - Self::ONE
33 } else {
34 self + Self::ONE
35 })
36 }
37}
38
39impl FromSciString for Integer {
40 /// Converts a string, possibly in scientfic notation, to an [`Integer`].
41 ///
42 /// Use [`FromSciStringOptions`] to specify the base (from 2 to 36, inclusive) and the rounding
43 /// mode, in case rounding is necessary because the string represents a non-integer.
44 ///
45 /// If the base is greater than 10, the higher digits are represented by the letters `'a'`
46 /// through `'z'` or `'A'` through `'Z'`; the case doesn't matter and doesn't need to be
47 /// consistent.
48 ///
49 /// Exponents are allowed, and are indicated using the character `'e'` or `'E'`. If the base is
50 /// 15 or greater, an ambiguity arises where it may not be clear whether `'e'` is a digit or an
51 /// exponent indicator. To resolve this ambiguity, always use a `'+'` or `'-'` sign after the
52 /// exponent indicator when the base is 15 or greater.
53 ///
54 /// The exponent itself is always parsed using base 10.
55 ///
56 /// Decimal (or other-base) points are allowed. These are most useful in conjunction with
57 /// exponents, but they may be used on their own. If the string represents a non-integer, the
58 /// rounding mode specified in `options` is used to round to an integer.
59 ///
60 /// If the string is unparseable, `None` is returned. `None` is also returned if the rounding
61 /// mode in options is `Exact`, but rounding is necessary.
62 ///
63 /// # Worst-case complexity
64 /// $T(n, m) = O(B (\log B)^2 \log\log B)$
65 ///
66 /// $M(n, m) = O(B \log B)$
67 ///
68 /// where $T$ is time, $M$ is additional memory, $n$ is `s.len()`, $m$ is `options.base`, and
69 /// $B$ is $10^n \log m$, a bound on the bit length of the result: the exponent is parsed in
70 /// base 10, so a string of length $n$ can denote a number of up to about $10^n \log_2 m$ bits,
71 /// and building it costs one power and one multiplication at that size.
72 ///
73 /// # Examples
74 /// ```
75 /// use malachite_base::num::conversion::string::options::FromSciStringOptions;
76 /// use malachite_base::num::conversion::traits::FromSciString;
77 /// use malachite_base::rounding_modes::RoundingMode::*;
78 /// use malachite_nz::integer::Integer;
79 ///
80 /// assert_eq!(Integer::from_sci_string("123").unwrap(), 123);
81 /// assert_eq!(Integer::from_sci_string("123.5").unwrap(), 124);
82 /// assert_eq!(Integer::from_sci_string("-123.5").unwrap(), -124);
83 /// assert_eq!(Integer::from_sci_string("1.23e10").unwrap(), 12300000000i64);
84 ///
85 /// let mut options = FromSciStringOptions::default();
86 /// assert_eq!(
87 /// Integer::from_sci_string_with_options("123.5", options).unwrap(),
88 /// 124
89 /// );
90 ///
91 /// options.set_rounding_mode(Floor);
92 /// assert_eq!(
93 /// Integer::from_sci_string_with_options("123.5", options).unwrap(),
94 /// 123
95 /// );
96 ///
97 /// options = FromSciStringOptions::default();
98 /// options.set_base(16);
99 /// assert_eq!(
100 /// Integer::from_sci_string_with_options("ff", options).unwrap(),
101 /// 255
102 /// );
103 /// ```
104 #[inline]
105 fn from_sci_string_with_options(s: &str, options: FromSciStringOptions) -> Option<Self> {
106 from_sci_string_with_options_helper(s, options)
107 }
108}