malachite_float/
lib.rs

1// Copyright © 2025 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
9//! This crate defines [`Float`]s, which are arbitrary-precision floating-point numbers.
10//!
11//! [`Float`]s are currently experimental. They are missing many important functions. However, the
12//! functions that are currently implemented are thoroughly tested and documented, with the
13//! exception of string conversion functions. The current string conversions are incomplete and
14//! will be changed in the future to match MPFR's behavior.
15//!
16//! # Demos and benchmarks
17//! This crate comes with a `bin` target that can be used for running demos and benchmarks.
18//! - Almost all of the public functions in this crate have an associated demo. Running a demo
19//!   shows you a function's behavior on a large number of inputs. TODO
20//! - You can use a similar command to run benchmarks. TODO
21//!
22//! The list of available demos and benchmarks is not documented anywhere; you must find them by
23//! browsing through
24//! [`bin_util/demo_and_bench`](https://github.com/mhogrefe/malachite/tree/master/malachite-float/src/bin_util/demo_and_bench).
25//!
26//! # Features
27//! - `32_bit_limbs`: Sets the type of [`Limb`](malachite_nz#limbs) to [`u32`] instead of the
28//!   default, [`u64`].
29//! - `test_build`: A large proportion of the code in this crate is only used for testing. For a
30//!   typical user, building this code would result in an unnecessarily long compilation time and
31//!   an unnecessarily large binary. My solution is to only build this code when the `test_build`
32//!   feature is enabled. If you want to run unit tests, you must enable `test_build`. However,
33//!   doctests don't require it, since they only test the public interface.
34//! - `bin_build`: This feature is used to build the code for demos and benchmarks, which also
35//!   takes a long time to build. Enabling this feature also enables `test_build`.
36
37#![allow(
38    unstable_name_collisions,
39    clippy::assertions_on_constants,
40    clippy::cognitive_complexity,
41    clippy::many_single_char_names,
42    clippy::range_plus_one,
43    clippy::suspicious_arithmetic_impl,
44    clippy::suspicious_op_assign_impl,
45    clippy::too_many_arguments,
46    clippy::type_complexity,
47    clippy::upper_case_acronyms,
48    clippy::multiple_bound_locations
49)]
50#![warn(
51    clippy::cast_lossless,
52    clippy::explicit_into_iter_loop,
53    clippy::explicit_iter_loop,
54    clippy::filter_map_next,
55    clippy::large_digit_groups,
56    clippy::manual_filter_map,
57    clippy::manual_find_map,
58    clippy::map_flatten,
59    clippy::map_unwrap_or,
60    clippy::match_same_arms,
61    clippy::missing_const_for_fn,
62    clippy::mut_mut,
63    clippy::needless_borrow,
64    clippy::needless_continue,
65    clippy::needless_pass_by_value,
66    clippy::print_stdout,
67    clippy::redundant_closure_for_method_calls,
68    clippy::single_match_else,
69    clippy::trait_duplication_in_bounds,
70    clippy::type_repetition_in_bounds,
71    clippy::uninlined_format_args,
72    clippy::unused_self,
73    clippy::if_not_else,
74    clippy::manual_assert,
75    clippy::range_plus_one,
76    clippy::redundant_else,
77    clippy::semicolon_if_nothing_returned,
78    clippy::cloned_instead_of_copied,
79    clippy::flat_map_option,
80    clippy::unnecessary_wraps,
81    clippy::unnested_or_patterns,
82    clippy::use_self,
83    clippy::trivially_copy_pass_by_ref
84)]
85#![cfg_attr(
86    not(any(feature = "test_build", feature = "random", feature = "std")),
87    no_std
88)]
89
90extern crate alloc;
91
92#[macro_use]
93extern crate malachite_base;
94
95#[cfg(feature = "test_build")]
96extern crate itertools;
97
98#[cfg(feature = "test_build")]
99use crate::InnerFloat::Finite;
100use core::cmp::Ordering::{self, *};
101use core::ops::Deref;
102#[cfg(feature = "test_build")]
103use malachite_base::num::arithmetic::traits::DivisibleByPowerOf2;
104use malachite_base::num::arithmetic::traits::IsPowerOf2;
105use malachite_base::num::basic::floats::PrimitiveFloat;
106use malachite_base::num::basic::integers::PrimitiveInt;
107use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom, SciMantissaAndExponent};
108#[cfg(feature = "test_build")]
109use malachite_base::num::logic::traits::SignificantBits;
110use malachite_base::rounding_modes::RoundingMode::*;
111use malachite_nz::natural::Natural;
112use malachite_nz::platform::Limb;
113use malachite_q::Rational;
114
115/// A floating-point number.
116///
117/// `Float`s are currently experimental. They are missing many important functions. However, the
118/// functions that are currently implemented are thoroughly tested and documented, with the
119/// exception of string conversion functions. The current string conversions are incomplete and will
120/// be changed in the future to match MPFR's behavior.
121///
122/// `Float`s are similar to the primitive floats defined by the IEEE 754 standard. They include NaN,
123/// positive and $-\infty$, and positive and negative zero. There is only one NaN; there is no
124/// concept of a NaN payload.
125///
126/// All the finite `Float`s are dyadic rationals (rational numbers whose denominator is a power of
127/// 2). A finite `Float` consists of several fields:
128/// - a sign, which denotes whether the `Float` is positive or negative;
129/// - a significand, which is a [`Natural`] number whose value is equal to the `Float`'s absolute
130///   value multiplied by a power of 2;
131/// - an exponent, which is one more than the floor of the base-2 logarithm of the `Float`'s
132///   absolute value;
133/// - and finally, a precision, which is greater than zero and indicates the number of significant
134///   bits. It is common to think of a `Float` as an approximation to some real number, and the
135///   precision indicates how good the approximation is intended to be.
136///
137/// `Float`s inherit some odd behavior from the IEEE 754 standard regarding comparison. A `NaN` is
138/// not equal to any `Float`, including itself. Positive and negative zero compare as equal, despite
139/// being two distinct values. Additionally, (and this is not IEEE 754's fault), `Float`s with
140/// different precisions compare as equal if they represent the same numeric value.
141///
142/// In many cases, the above behavior is unsatisfactory, so the [`ComparableFloat`] and
143/// [`ComparableFloat`] wrappers are provided. See their documentation for a description of their
144/// comparison behavior.
145///
146/// In documentation, we will use the '$=$' sign to mean that two `Float`s are identical, writing
147/// things like $-\text{NaN}=\text{NaN}$ and $-(0.0) = -0.0$.
148///
149/// The `Float` type is designed to be very similar to the `mpfr_t` type in
150/// [MPFR](https://www.mpfr.org/mpfr-current/mpfr.html#Nomenclature-and-Types), and all Malachite
151/// functions produce exactly the same result as their counterparts in MPFR, unless otherwise noted.
152///
153/// Here are the structural difference between `Float` and `mpfr_t`:
154/// - `Float` can only represent a single `NaN` value, with no sign or payload.
155/// - Only finite, nonzero `Float`s have a significand, precision, and exponent. For other `Float`s,
156///   these concepts are undefined. In particular, unlike `mpfr_t` zeros, `Float` zeros do not have
157///   a precision.
158/// - The types of `mpfr_t` components are configuration- and platform-dependent. The types of
159///   `Float` components are platform-independent, although the `Limb` type is
160///   configuration-dependent: it is `u64` by default, but may be changed to `u32` using the
161///   `--32_bit_limbs` compiler flag. The type of the exponent is always `i32` and the type of the
162///   precision is always `u64`. The `Limb` type only has a visible effect on the functions that
163///   extract the raw significand. All other functions have the same interface when compiled with
164///   either `Limb` type.
165///
166/// `Float`s whose precision is 64 bits or less can be represented without any memory allocation.
167/// (Unless Malachite is compiled with `32_bit_limbs`, in which case the limit is 32).
168#[derive(Clone)]
169pub struct Float(pub(crate) InnerFloat);
170
171// We want to limit the visibility of the `NaN`, `Zero`, `Infinity`, and `Finite` constructors to
172// within this crate. To do this, we wrap the `InnerFloat` enum in a struct that gets compiled away.
173#[derive(Clone)]
174pub(crate) enum InnerFloat {
175    NaN,
176    Infinity {
177        sign: bool,
178    },
179    Zero {
180        sign: bool,
181    },
182    Finite {
183        sign: bool,
184        exponent: i32,
185        precision: u64,
186        significand: Natural,
187    },
188}
189
190#[inline]
191pub(crate) fn significand_bits(significand: &Natural) -> u64 {
192    significand.limb_count() << Limb::LOG_WIDTH
193}
194
195impl Float {
196    /// The maximum raw exponent of any [`Float`], equal to $2^{30}-1$, or $1,073,741,823$. This is
197    /// one more than the maximum scientific exponent. If we write a [`Float`] as $\pm m2^e$, with
198    /// $1\leq m<2$ and $e$ an integer, we must have $e\leq 2^{30}-2$. If the result of a
199    /// calculation would produce a [`Float`] with an exponent larger than this, then $\pm\infty$,
200    /// the maximum finite float of the specified precision, or the minimum finite float of the
201    /// specified pecision is returned instead, depending on the rounding mode.
202    pub const MAX_EXPONENT: i32 = 0x3fff_ffff;
203    /// The minimum raw exponent of any [`Float`], equal to $-(2^{30}-1)$, or $-1,073,741,823$. This
204    /// is one more than the minimum scientific exponent. If we write a [`Float`] as $\pm m2^e$,
205    /// with $1\leq m<2$ and $e$ an integer, we must have $e\geq -2^{30}$. If the result of a
206    /// calculation would produce a [`Float`] with an exponent smaller than this, then $\pm0.0$, the
207    /// minimum positive finite [`Float`], or the maximum negative finite [`Float`] is returned
208    /// instead, depending on the rounding mode.
209    pub const MIN_EXPONENT: i32 = -Self::MAX_EXPONENT;
210
211    #[cfg(feature = "test_build")]
212    pub fn is_valid(&self) -> bool {
213        match self {
214            Self(Finite {
215                precision,
216                significand,
217                exponent,
218                ..
219            }) => {
220                if *precision == 0
221                    || !significand.is_valid()
222                    || *exponent > Self::MAX_EXPONENT
223                    || *exponent < Self::MIN_EXPONENT
224                {
225                    return false;
226                }
227                let bits = significand.significant_bits();
228                bits != 0
229                    && bits.divisible_by_power_of_2(Limb::LOG_WIDTH)
230                    && *precision <= bits
231                    && bits - precision < Limb::WIDTH
232                    && significand.divisible_by_power_of_2(bits - precision)
233            }
234            _ => true,
235        }
236    }
237}
238
239/// `ComparableFloat` is a wrapper around a [`Float`], taking the [`Float`] by value.
240///
241/// `CompatableFloat` has different comparison behavior than [`Float`]. See the [`Float`]
242/// documentation for its comparison behavior, which is largely derived from the IEEE 754
243/// specification; the `ComparableFloat` behavior, on the other hand, is more mathematically
244/// well-behaved, and respects the principle that equality should be the finest equivalence
245/// relation: that is, that two equal objects should not be different in any way.
246///
247/// To be more specific: when a [`Float`] is wrapped in a `ComparableFloat`,
248/// - `NaN` is not equal to any other [`Float`], but equal to itself;
249/// - Positive and negative zero are not equal to each other;
250/// - Ordering is total. Negative zero is ordered to be smaller than positive zero, and `NaN` is
251///   arbitrarily ordered to be between the two zeros;
252/// - Two [`Float`]s with different precisions but representing the same value are unequal, and the
253///   one with the greater precision is ordered to be larger;
254/// - The hashing function is compatible with equality.
255///
256/// The analogous wrapper for primitive floats is
257/// [`NiceFloat`](malachite_base::num::float::NiceFloat). However,
258/// [`NiceFloat`](malachite_base::num::float::NiceFloat) also facilitates better string conversion,
259/// something that isn't necessary for [`Float`]s
260///
261/// `ComparableFloat` owns its float. This is useful in many cases, for example if you want to use
262/// [`Float`]s as keys in a hash map. In other situations, it is better to use
263/// [`ComparableFloatRef`], which only has a reference to its float.
264#[derive(Clone)]
265pub struct ComparableFloat(pub Float);
266
267/// `ComparableFloatRef` is a wrapper around a [`Float`], taking the [`Float`] be reference.
268///
269/// See the [`ComparableFloat`] documentation for details.
270#[derive(Clone)]
271pub struct ComparableFloatRef<'a>(pub &'a Float);
272
273impl ComparableFloat {
274    pub const fn as_ref(&self) -> ComparableFloatRef<'_> {
275        ComparableFloatRef(&self.0)
276    }
277}
278
279impl Deref for ComparableFloat {
280    type Target = Float;
281
282    /// Allows a [`ComparableFloat`] to dereference to a [`Float`].
283    ///
284    /// ```
285    /// use malachite_base::num::basic::traits::One;
286    /// use malachite_float::{ComparableFloat, Float};
287    ///
288    /// let x = ComparableFloat(Float::ONE);
289    /// assert_eq!(*x, Float::ONE);
290    /// ```
291    fn deref(&self) -> &Float {
292        &self.0
293    }
294}
295
296impl Deref for ComparableFloatRef<'_> {
297    type Target = Float;
298
299    /// Allows a [`ComparableFloatRef`] to dereference to a [`Float`].
300    ///
301    /// ```
302    /// use malachite_base::num::basic::traits::One;
303    /// use malachite_float::{ComparableFloatRef, Float};
304    ///
305    /// let x = Float::ONE;
306    /// let y = ComparableFloatRef(&x);
307    /// assert_eq!(*y, Float::ONE);
308    /// ```
309    fn deref(&self) -> &Float {
310        self.0
311    }
312}
313
314#[allow(clippy::type_repetition_in_bounds)]
315#[doc(hidden)]
316pub fn emulate_float_to_float_fn<T: PrimitiveFloat, F: Fn(Float, u64) -> (Float, Ordering)>(
317    f: F,
318    x: T,
319) -> T
320where
321    Float: From<T> + PartialOrd<T>,
322    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
323{
324    let x = Float::from(x);
325    let (mut result, o) = f(x.clone(), T::MANTISSA_WIDTH + 1);
326    if !result.is_normal() {
327        return T::exact_from(&result);
328    }
329    let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
330    if e < T::MIN_NORMAL_EXPONENT {
331        if e < T::MIN_EXPONENT {
332            let rm =
333                if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
334                    let down = if result > T::ZERO { Less } else { Greater };
335                    if o == down { Up } else { Down }
336                } else {
337                    Nearest
338                };
339            return T::rounding_from(&result, rm).0;
340        }
341        result = f(x, T::max_precision_for_sci_exponent(e)).0;
342    }
343    if result > T::MAX_FINITE {
344        T::INFINITY
345    } else if result < -T::MAX_FINITE {
346        T::NEGATIVE_INFINITY
347    } else {
348        T::exact_from(&result)
349    }
350}
351
352#[allow(clippy::type_repetition_in_bounds)]
353#[doc(hidden)]
354pub fn emulate_float_float_to_float_fn<
355    T: PrimitiveFloat,
356    F: Fn(Float, Float, u64) -> (Float, Ordering),
357>(
358    f: F,
359    x: T,
360    y: T,
361) -> T
362where
363    Float: From<T> + PartialOrd<T>,
364    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
365{
366    let x = Float::from(x);
367    let y = Float::from(y);
368    let (mut result, o) = f(x.clone(), y.clone(), T::MANTISSA_WIDTH + 1);
369    if !result.is_normal() {
370        return T::exact_from(&result);
371    }
372    let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
373    if e < T::MIN_NORMAL_EXPONENT {
374        if e < T::MIN_EXPONENT {
375            let rm =
376                if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
377                    let down = if result > T::ZERO { Less } else { Greater };
378                    if o == down { Up } else { Down }
379                } else {
380                    Nearest
381                };
382            return T::rounding_from(&result, rm).0;
383        }
384        result = f(x, y, T::max_precision_for_sci_exponent(e)).0;
385    }
386    if result > T::MAX_FINITE {
387        T::INFINITY
388    } else if result < -T::MAX_FINITE {
389        T::NEGATIVE_INFINITY
390    } else {
391        T::exact_from(&result)
392    }
393}
394
395#[allow(clippy::type_repetition_in_bounds)]
396#[doc(hidden)]
397pub fn emulate_rational_to_float_fn<T: PrimitiveFloat, F: Fn(&Rational, u64) -> (Float, Ordering)>(
398    f: F,
399    x: &Rational,
400) -> T
401where
402    Float: PartialOrd<T>,
403    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
404{
405    let (mut result, o) = f(x, T::MANTISSA_WIDTH + 1);
406    if !result.is_normal() {
407        return T::exact_from(&result);
408    }
409    let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
410    if e < T::MIN_NORMAL_EXPONENT {
411        if e < T::MIN_EXPONENT {
412            let rm =
413                if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
414                    let down = if result > T::ZERO { Less } else { Greater };
415                    if o == down { Up } else { Down }
416                } else {
417                    Nearest
418                };
419            return T::rounding_from(&result, rm).0;
420        }
421        result = f(x, T::max_precision_for_sci_exponent(e)).0;
422    }
423    if result > T::MAX_FINITE {
424        T::INFINITY
425    } else if result < -T::MAX_FINITE {
426        T::NEGATIVE_INFINITY
427    } else {
428        T::exact_from(&result)
429    }
430}
431
432/// Traits for arithmetic.
433pub mod arithmetic;
434#[macro_use]
435/// Basic traits for working with [`Float`]s.
436pub mod basic;
437/// Traits for comparing [`Float`]s for equality or order.
438pub mod comparison;
439/// Functions that produce [`Float`] approximations of mathematical constants, using a given
440/// precision and rounding mode.
441pub mod constants;
442/// Traits for converting to and from [`Float`]s, including converting [`Float`]s to and from
443/// strings.
444pub mod conversion;
445/// Iterators that generate [`Float`]s without repetition.
446pub mod exhaustive;
447#[cfg(feature = "random")]
448/// Iterators that generate [`Float`]s randomly.
449pub mod random;
450
451#[cfg(feature = "test_build")]
452pub mod test_util;