Skip to main content

hugefloat/
lib.rs

1//! `hugefloat` provides a numeric type that acts like [`f64`] with a much
2//! higher maximum value.
3//!
4//! This library is NOT intended for usecases that actually require precise
5//! arithmetic. Use [`gmp`] or [`rug`] if you need that. `hugefloat` is
6//! designed to be lightweight and have no foreign dependencies so it can easily
7//! be compiled to WASM. It's intended for use in incremental and idle games
8//! which must handle extremely large numbers.
9//!
10//! # Features
11//!
12//! Enable the `serde` feature of this crate to support de/serialization via
13//! serde.
14//!
15//! [`gmp`]: https://crates.io/crates/gmp
16//! [`rug`]: https://crates.io/crates/rug
17
18use std::{
19  cmp::Ordering,
20  f64::consts,
21  fmt::{self, Display},
22  ops::*,
23  str::FromStr,
24};
25use thiserror::Error;
26
27#[cfg(feature = "serde")] mod serde;
28mod table;
29
30/// Parsing a `Float` can fail either while parsing the base (which is a
31/// float) or the exponent (which is an int).
32#[derive(Error, Debug, Eq, PartialEq, Clone)]
33pub enum ParseError {
34  #[error("{0}")]
35  Float(#[from] std::num::ParseFloatError),
36  #[error("{0}")]
37  Int(#[from] std::num::ParseIntError),
38}
39
40/// A number that behaves mostly like a float, but with an extremely large
41/// maximum value.
42///
43/// To construct a `Float` outside the range of `f64`, use either
44/// [`Float::sci`] or the [`FromStr`] implementation.
45///
46/// ```
47/// # use hugefloat::Float;
48/// assert_eq!("1".parse(), Ok(Float::sci(1.0, 0)));
49/// assert_eq!("1e10000".parse(), Ok(Float::sci(1.0, 10000)));
50/// ```
51#[derive(Debug, Copy, Clone, PartialEq)]
52pub struct Float {
53  mantissa: f64,
54  exponent: i64,
55}
56
57const MAX_DIGITS: i64 = 17;
58const MAX_EXPONENT: i64 = 9_000_000_000_000_000;
59
60impl Float {
61  /// The largest value that `Float` can represent:
62  /// `1e9_000_000_000_000_000`.
63  pub const MAX: Float = Float {
64    exponent: MAX_EXPONENT,
65    mantissa: 1.0,
66  };
67  /// The smallest value that `Float` can represent. Equivalent to `-MAX`.
68  pub const MIN: Float = Float {
69    exponent: MAX_EXPONENT,
70    mantissa: -1.0,
71  };
72  pub const NAN: Float = Float {
73    exponent: 0,
74    mantissa: std::f64::NAN,
75  };
76
77  pub fn mantissa(self) -> f64 {
78    self.mantissa
79  }
80
81  pub fn exponent(self) -> i64 {
82    self.exponent
83  }
84
85  #[doc(hidden)]
86  pub fn normalize(mut self) -> Self {
87    if !self.mantissa.is_finite() {
88      return self;
89    }
90    while self.mantissa.abs() < 1.0 && self.mantissa != 0.0 {
91      self.mantissa *= 10.0;
92      self.exponent -= 1;
93    }
94    while self.mantissa.abs() >= 10.0 {
95      self.mantissa /= 10.0;
96      self.exponent += 1;
97    }
98    self
99  }
100
101  /// Construct a `Float` from a base and exponent.
102  pub fn sci(base: f64, exponent: i64) -> Self {
103    if !base.is_finite() {
104      Self::NAN
105    } else {
106      Float {
107        mantissa: base,
108        exponent,
109      }
110      .normalize()
111    }
112  }
113
114  /// Convert a regular float to a `Float`.
115  pub fn float(value: f64) -> Self {
116    if value.is_nan() {
117      Self::NAN
118    } else if value.is_infinite() {
119      if value.is_sign_positive() {
120        Self::MAX
121      } else {
122        Self::MIN
123      }
124    } else if value == 0.0 || value == -0.0 {
125      Float {
126        mantissa: 0.0,
127        exponent: 0,
128      }
129    } else {
130      let exponent = value.abs().log10().floor() as i64;
131      let base = table::POWERS[(exponent + table::TABLE_CENTER as i64) as usize];
132      let mantissa = value / base;
133      Float { exponent, mantissa }.normalize()
134    }
135  }
136
137  /// Convert an integer value to a `Float`.
138  pub fn int(value: i64) -> Self {
139    Self::float(value as f64)
140  }
141
142  /// Try to convert `self` to `f64`. `None` if `self` does not fit in f64, i.e.
143  /// if it's higher than `f64::MAX` or lower than `f64::MIN`.
144  pub fn try_float(self) -> Option<f64> {
145    let f = self.to_float();
146    if !f.is_finite() {
147      None
148    } else {
149      Some(f)
150    }
151  }
152
153  /// Like `try_float`, but overflows will be represented as positive or
154  /// negative infinity.
155  ///
156  /// ```
157  /// # use hugefloat::Float;
158  /// assert_eq!(Float::sci(1.0, 10).to_float(), 1.0e10);
159  /// assert!(Float::sci(1.0, 10000).to_float().is_infinite());
160  /// ```
161  pub fn to_float(self) -> f64 {
162    dbg!(self.mantissa) * dbg!(10.0f64.powi(dbg!(self.exponent as i32)))
163  }
164
165  pub fn abs(mut self) -> Self {
166    self.mantissa = self.mantissa.abs();
167    self
168  }
169
170  pub fn signum(self) -> f64 {
171    self.mantissa.signum()
172  }
173
174  pub fn recip(self) -> Self {
175    Self::sci(1.0 / self.mantissa, -self.exponent)
176  }
177
178  pub fn round(self) -> Self {
179    if self.exponent.abs() < 308 {
180      Self::float(self.to_float().round())
181    } else {
182      self
183    }
184  }
185
186  pub fn floor(self) -> Self {
187    if self.exponent.abs() < 308 {
188      Self::float(self.to_float().floor())
189    } else {
190      self
191    }
192  }
193
194  pub fn ceil(self) -> Self {
195    if self.exponent.abs() < 308 {
196      Self::float(self.to_float().ceil())
197    } else {
198      self
199    }
200  }
201
202  pub fn trunc(self) -> Self {
203    if self.exponent.abs() < 308 {
204      Self::float(self.to_float().trunc())
205    } else {
206      self
207    }
208  }
209
210  pub fn log10(self) -> f64 {
211    (self.exponent as f64) + self.mantissa.log10()
212  }
213
214  pub fn log2(self) -> f64 {
215    self.log10() * consts::LOG2_10
216  }
217
218  pub fn ln(self) -> f64 {
219    self.log10() * consts::LN_10
220  }
221
222  /// This method panics if `base < 2.0`.
223  pub fn log(self, base: f64) -> f64 {
224    assert!(
225      base >= 2.0,
226      "cannot call Float::log() with a base lower than 2"
227    );
228    (consts::LN_10 / base.ln()) * self.log10()
229  }
230
231  pub fn powf(self, n: f64) -> Self {
232    Self::float(n * self.ln()).exp()
233  }
234
235  pub fn powi(self, n: i32) -> Self {
236    Self::sci(self.mantissa.powi(n), self.exponent * (n as i64))
237  }
238
239  pub fn exp(self) -> Self {
240    let f = self.to_float();
241    if -706.0 < f && f < 709.0 {
242      Self::float(f.exp())
243    } else {
244      let mut x = self;
245      let mut exp = 0f64;
246      let expx = self.exponent;
247      let ln10 = Self::float(consts::LN_10);
248
249      if expx >= 0 {
250        exp = (x / ln10).to_float().trunc();
251        let tmp = Self::float(exp) * ln10;
252        x -= tmp;
253        if x >= ln10 {
254          exp += 1.0;
255          x -= ln10;
256        }
257      }
258      if x.signum() < 0.0 {
259        exp -= 1.0;
260        x += ln10;
261      }
262
263      let nextx = x.to_float().exp();
264
265      if exp != 0.0 {
266        x = Self::sci(nextx, exp.floor() as i64);
267      }
268
269      x
270    }
271  }
272
273  pub fn sqrt(self) -> Self {
274    self.powf(0.5)
275  }
276
277  pub fn cbrt(self) -> Self {
278    self.powf(1.0 / 3.0)
279  }
280}
281
282impl From<i64> for Float {
283  fn from(i: i64) -> Self {
284    Self::int(i)
285  }
286}
287
288impl From<f64> for Float {
289  fn from(f: f64) -> Self {
290    Self::float(f)
291  }
292}
293
294impl FromStr for Float {
295  type Err = ParseError;
296
297  fn from_str(input: &str) -> Result<Self, Self::Err> {
298    let mut sci_parts = input.splitn(2, 'e');
299    let first = sci_parts
300      .next()
301      .expect("split should never yield zero elements");
302    if let Some(second) = sci_parts.next() {
303      Ok(Self::sci(first.parse()?, second.parse()?))
304    } else {
305      Ok(Self::float(first.parse()?))
306    }
307  }
308}
309
310impl Display for Float {
311  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312    let Float { mantissa, exponent } = *self;
313    if mantissa.is_nan() {
314      write!(f, "NaN")
315    } else if exponent >= MAX_EXPONENT {
316      if mantissa.is_sign_positive() {
317        write!(f, "Infinity")
318      } else {
319        write!(f, "-Infinity")
320      }
321    } else if exponent <= -MAX_EXPONENT || mantissa == 0.0 {
322      write!(f, "0")
323    } else if exponent >= MAX_DIGITS as i64 {
324      write!(
325        f,
326        "{value:0<prec$}",
327        value = mantissa.to_string().replace(".", ""),
328        prec = (exponent as usize) + 1
329      )
330    } else {
331      write!(
332        f,
333        "{value:.prec$}",
334        value = self.to_float(),
335        prec = f.precision().unwrap_or(0)
336      )
337    }
338  }
339}
340
341impl fmt::LowerExp for Float {
342  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
343    format_exp(*self, 'e', f)
344  }
345}
346
347impl fmt::UpperExp for Float {
348  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
349    format_exp(*self, 'E', f)
350  }
351}
352
353fn format_exp(h: Float, chr: char, f: &mut fmt::Formatter) -> fmt::Result {
354  let Float { mantissa, exponent } = h;
355  if mantissa.is_nan() {
356    write!(f, "NaN")
357  } else if exponent >= MAX_EXPONENT {
358    if mantissa.is_sign_positive() {
359      write!(f, "Infinity")
360    } else {
361      write!(f, "-Infinity")
362    }
363  } else if exponent <= -MAX_EXPONENT || mantissa == 0.0 {
364    write!(f, "0")
365  } else {
366    write!(
367      f,
368      "{base:.prec$}{e}{exp}",
369      e = chr,
370      base = mantissa,
371      exp = exponent,
372      prec = f.precision().unwrap_or(0)
373    )
374  }
375}
376
377impl Neg for Float {
378  type Output = Self;
379
380  fn neg(self) -> Self::Output {
381    Self::sci(-self.mantissa, self.exponent)
382  }
383}
384
385impl Add<Float> for Float {
386  type Output = Self;
387
388  fn add(self, other: Self) -> Self::Output {
389    let (bigger, smaller) = if self.exponent >= other.exponent {
390      (self, other)
391    } else {
392      (other, self)
393    };
394    if bigger.exponent - smaller.exponent > MAX_DIGITS as i64 {
395      bigger
396    } else {
397      let factor =
398        table::POWERS[((smaller.exponent - bigger.exponent) + table::TABLE_CENTER as i64) as usize];
399      Self::sci(bigger.mantissa + smaller.mantissa * factor, bigger.exponent)
400    }
401  }
402}
403
404impl Add<i64> for Float {
405  type Output = Self;
406
407  fn add(self, other: i64) -> Self::Output {
408    self + Self::int(other)
409  }
410}
411
412impl Add<f64> for Float {
413  type Output = Self;
414
415  fn add(self, other: f64) -> Self::Output {
416    self + Self::float(other)
417  }
418}
419
420impl<T> AddAssign<T> for Float
421where
422  Float: Add<T, Output = Float>,
423{
424  fn add_assign(&mut self, other: T) {
425    *self = self.add(other)
426  }
427}
428
429impl Sub<Float> for Float {
430  type Output = Self;
431
432  fn sub(self, other: Float) -> Self::Output {
433    self + -other
434  }
435}
436
437impl Sub<i64> for Float {
438  type Output = Self;
439
440  fn sub(self, other: i64) -> Self::Output {
441    self + -other
442  }
443}
444
445impl Sub<f64> for Float {
446  type Output = Self;
447
448  fn sub(self, other: f64) -> Self::Output {
449    self + -other
450  }
451}
452
453impl<T> SubAssign<T> for Float
454where
455  Float: Sub<T, Output = Float>,
456{
457  fn sub_assign(&mut self, other: T) {
458    *self = self.sub(other)
459  }
460}
461
462impl Mul<Float> for Float {
463  type Output = Self;
464
465  #[allow(clippy::suspicious_arithmetic_impl)]
466  fn mul(self, other: Self) -> Self::Output {
467    Self::sci(
468      self.mantissa * other.mantissa,
469      self.exponent + other.exponent,
470    )
471  }
472}
473
474impl Mul<i64> for Float {
475  type Output = Self;
476
477  fn mul(self, other: i64) -> Self::Output {
478    self * Self::int(other)
479  }
480}
481
482impl Mul<f64> for Float {
483  type Output = Self;
484
485  fn mul(self, other: f64) -> Self::Output {
486    self * Self::float(other)
487  }
488}
489
490impl<T> MulAssign<T> for Float
491where
492  Float: Mul<T, Output = Float>,
493{
494  fn mul_assign(&mut self, other: T) {
495    *self = self.mul(other)
496  }
497}
498
499impl Div<Float> for Float {
500  type Output = Self;
501
502  #[allow(clippy::suspicious_arithmetic_impl)]
503  fn div(self, other: Self) -> Self::Output {
504    self * other.recip()
505  }
506}
507
508impl Div<i64> for Float {
509  type Output = Self;
510
511  fn div(self, other: i64) -> Self::Output {
512    self / Self::int(other)
513  }
514}
515
516impl Div<f64> for Float {
517  type Output = Self;
518
519  fn div(self, other: f64) -> Self::Output {
520    self / Self::float(other)
521  }
522}
523
524impl<T> DivAssign<T> for Float
525where
526  Float: Div<T, Output = Float>,
527{
528  fn div_assign(&mut self, other: T) {
529    *self = self.div(other)
530  }
531}
532
533impl PartialOrd for Float {
534  fn partial_cmp(&self, value: &Self) -> Option<Ordering> {
535    if !self.mantissa.is_finite() || !value.mantissa.is_finite() {
536      return None;
537    }
538    if self.mantissa == 0.0 || value.mantissa == 0.0 {
539      return self.mantissa.partial_cmp(&value.mantissa);
540    }
541    if self.mantissa > 0.0 {
542      if value.mantissa < 0.0 {
543        return Some(Ordering::Greater);
544      }
545      if self.exponent > value.exponent {
546        return Some(Ordering::Greater);
547      }
548      if self.exponent < value.exponent {
549        return Some(Ordering::Less);
550      }
551      if self.mantissa > value.mantissa {
552        return Some(Ordering::Greater);
553      }
554      if self.mantissa < value.mantissa {
555        return Some(Ordering::Less);
556      }
557      return Some(Ordering::Equal);
558    } else if self.mantissa < 0.0 {
559      if value.mantissa > 0.0 {
560        return Some(Ordering::Less);
561      }
562      if self.exponent > value.exponent {
563        return Some(Ordering::Less);
564      }
565      if self.exponent < value.exponent {
566        return Some(Ordering::Greater);
567      }
568      if self.mantissa > value.mantissa {
569        return Some(Ordering::Less);
570      }
571      if self.mantissa < value.mantissa {
572        return Some(Ordering::Greater);
573      }
574      return Some(Ordering::Equal);
575    }
576    None
577  }
578}
579
580#[test]
581fn test_format() {
582  let h = Float::sci(1.0, 10);
583  assert_eq!(format!("{}", h), "10000000000");
584  assert_eq!(format!("{:.3}", h), "10000000000.000");
585
586  let h = Float::sci(1.0, 10000);
587  assert_eq!(format!("{:e}", h), "1e10000");
588  assert_eq!(format!("{:.3e}", h), "1.000e10000");
589  assert_eq!(format!("{:.3e}", h.powi(2)), "1.000e20000");
590}
591
592#[test]
593fn test_math_ops() {
594  let h = Float::float(1.234);
595  assert_eq!(-h, Float::float(-1.234));
596
597  // need rounding of course due to float imprecision
598  assert_eq!(Float::float(9.0).sqrt().round(), Float::float(3.0));
599  assert_eq!(Float::float(9.0).powf(2.0).round(), Float::float(81.0));
600
601  // exp > 308
602  let mut bignum = Float::sci(1.2345, 347);
603
604  bignum = bignum.powf(2.0);
605  assert_eq!(bignum, Float::sci(1.523990249999763, 694));
606  bignum = bignum.powf(56.1);
607  assert_eq!(bignum, Float::sci(4.627013609064963, 38943));
608}