malachite_float/lib.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
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#![forbid(unsafe_code)]
38#![allow(
39 unstable_name_collisions,
40 clippy::assertions_on_constants,
41 clippy::cognitive_complexity,
42 clippy::many_single_char_names,
43 clippy::range_plus_one,
44 clippy::suspicious_arithmetic_impl,
45 clippy::suspicious_op_assign_impl,
46 clippy::too_many_arguments,
47 clippy::type_complexity,
48 clippy::upper_case_acronyms,
49 clippy::multiple_bound_locations
50)]
51#![warn(
52 clippy::cast_lossless,
53 clippy::explicit_into_iter_loop,
54 clippy::explicit_iter_loop,
55 clippy::filter_map_next,
56 clippy::large_digit_groups,
57 clippy::manual_filter_map,
58 clippy::manual_find_map,
59 clippy::map_flatten,
60 clippy::map_unwrap_or,
61 clippy::match_same_arms,
62 clippy::missing_const_for_fn,
63 clippy::mut_mut,
64 clippy::needless_borrow,
65 clippy::needless_continue,
66 clippy::needless_pass_by_value,
67 clippy::print_stdout,
68 clippy::redundant_closure_for_method_calls,
69 clippy::single_match_else,
70 clippy::trait_duplication_in_bounds,
71 clippy::type_repetition_in_bounds,
72 clippy::uninlined_format_args,
73 clippy::unused_self,
74 clippy::if_not_else,
75 clippy::manual_assert,
76 clippy::range_plus_one,
77 clippy::redundant_else,
78 clippy::semicolon_if_nothing_returned,
79 clippy::cloned_instead_of_copied,
80 clippy::flat_map_option,
81 clippy::unnecessary_wraps,
82 clippy::unnested_or_patterns,
83 clippy::use_self,
84 clippy::trivially_copy_pass_by_ref
85)]
86#![cfg_attr(
87 not(any(feature = "test_build", feature = "random", feature = "std")),
88 no_std
89)]
90
91extern crate alloc;
92
93#[macro_use]
94extern crate malachite_base;
95
96#[cfg(feature = "test_build")]
97extern crate itertools;
98
99#[cfg(feature = "test_build")]
100use crate::InnerFloat::Finite;
101use core::cmp::Ordering::{self, *};
102use core::ops::Deref;
103#[cfg(feature = "test_build")]
104use malachite_base::num::arithmetic::traits::DivisibleByPowerOf2;
105use malachite_base::num::arithmetic::traits::IsPowerOf2;
106use malachite_base::num::basic::floats::PrimitiveFloat;
107use malachite_base::num::basic::integers::PrimitiveInt;
108use malachite_base::num::basic::traits::{Infinity, NegativeInfinity};
109use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom, SciMantissaAndExponent};
110#[cfg(feature = "test_build")]
111use malachite_base::num::logic::traits::SignificantBits;
112use malachite_base::rounding_modes::RoundingMode::*;
113use malachite_nz::natural::Natural;
114use malachite_nz::platform::Limb;
115use malachite_q::Rational;
116
117/// A floating-point number.
118///
119/// `Float`s are currently experimental. They are missing many important functions. However, the
120/// functions that are currently implemented are thoroughly tested and documented, with the
121/// exception of string conversion functions. The current string conversions are incomplete and will
122/// be changed in the future to match MPFR's behavior.
123///
124/// `Float`s are similar to the primitive floats defined by the IEEE 754 standard. They include NaN,
125/// $\infty$ and $-\infty$, and positive and negative zero. There is only one NaN; there is no
126/// concept of a NaN payload.
127///
128/// All the finite `Float`s are dyadic rationals (rational numbers whose denominator is a power of
129/// 2). A finite `Float` consists of several fields:
130/// - a sign, which denotes whether the `Float` is positive or negative;
131/// - a significand, which is a [`Natural`] number whose value is equal to the `Float`'s absolute
132/// value multiplied by a power of 2;
133/// - an exponent, which is one more than the floor of the base-2 logarithm of the `Float`'s
134/// absolute value;
135/// - and finally, a precision, which is greater than zero and indicates the number of significant
136/// bits. It is common to think of a `Float` as an approximation of some real number, and the
137/// precision indicates how good the approximation is intended to be.
138///
139/// `Float`s inherit some odd behavior from the IEEE 754 standard regarding comparison. A `NaN` is
140/// not equal to any `Float`, including itself. Positive and negative zero compare as equal, despite
141/// being two distinct values. Additionally, (and this is not IEEE 754's fault), `Float`s with
142/// different precisions compare as equal if they represent the same numeric value.
143///
144/// In many cases, the above behavior is unsatisfactory, so the [`ComparableFloat`] and
145/// [`ComparableFloat`] wrappers are provided. See their documentation for a description of their
146/// comparison behavior.
147///
148/// In documentation, we will use the '$=$' sign to mean that two `Float`s are identical, writing
149/// things like $-\text{NaN}=\text{NaN}$ and $-(0.0) = -0.0$.
150///
151/// The `Float` type is designed to be very similar to the `mpfr_t` type in
152/// [MPFR](https://www.mpfr.org/mpfr-current/mpfr.html#Nomenclature-and-Types), and all Malachite
153/// functions produce exactly the same result as their counterparts in MPFR, unless otherwise noted.
154///
155/// Here are the structural difference between `Float` and `mpfr_t`:
156/// - `Float` can only represent a single `NaN` value, with no sign or payload.
157/// - Only finite, nonzero `Float`s have a significand, precision, and exponent. For other `Float`s,
158/// these concepts are undefined. In particular, unlike `mpfr_t` zeros, `Float` zeros do not have
159/// a precision.
160/// - The types of `mpfr_t` components are configuration- and platform-dependent. The types of
161/// `Float` components are platform-independent, although the `Limb` type is
162/// configuration-dependent: it is `u64` by default, but may be changed to `u32` using the
163/// `--32_bit_limbs` compiler flag. The type of the exponent is always `i32` and the type of the
164/// precision is always `u64`. The `Limb` type only has a visible effect on the functions that
165/// extract the raw significand. All other functions have the same interface when compiled with
166/// either `Limb` type.
167///
168/// `Float`s whose precision is 64 bits or less can be represented without any memory allocation.
169/// (Unless Malachite is compiled with `32_bit_limbs`, in which case the limit is 32).
170#[derive(Clone)]
171pub struct Float(pub(crate) InnerFloat);
172
173// We want to limit the visibility of the `NaN`, `Zero`, `Infinity`, and `Finite` constructors to
174// within this crate. To do this, we wrap the `InnerFloat` enum in a struct that gets compiled away.
175#[derive(Clone)]
176pub(crate) enum InnerFloat {
177 NaN,
178 Infinity {
179 sign: bool,
180 },
181 Zero {
182 sign: bool,
183 },
184 Finite {
185 sign: bool,
186 exponent: i32,
187 precision: u64,
188 significand: Natural,
189 },
190}
191
192#[inline]
193pub(crate) fn significand_bits(significand: &Natural) -> u64 {
194 significand.limb_count() << Limb::LOG_WIDTH
195}
196
197impl Float {
198 /// The maximum raw exponent of any [`Float`], equal to $2^{30}-1$, or $1,073,741,823$. This is
199 /// one more than the maximum scientific exponent. If we write a [`Float`] as $\pm m2^e$, with
200 /// $1\leq m<2$ and $e$ an integer, we must have $e\leq 2^{30}-2$. If the result of a
201 /// calculation would produce a [`Float`] with an exponent larger than this, then $\pm\infty$,
202 /// the maximum finite float of the specified precision, or the minimum finite float of the
203 /// specified pecision is returned instead, depending on the rounding mode.
204 pub const MAX_EXPONENT: i32 = 0x3fff_ffff;
205 /// The minimum raw exponent of any [`Float`], equal to $-(2^{30}-1)$, or $-1,073,741,823$. This
206 /// is one more than the minimum scientific exponent. If we write a [`Float`] as $\pm m2^e$,
207 /// with $1\leq m<2$ and $e$ an integer, we must have $e\geq -2^{30}$. If the result of a
208 /// calculation would produce a [`Float`] with an exponent smaller than this, then $\pm0.0$, the
209 /// minimum positive finite [`Float`], or the maximum negative finite [`Float`] is returned
210 /// instead, depending on the rounding mode.
211 pub const MIN_EXPONENT: i32 = -Self::MAX_EXPONENT;
212
213 #[cfg(feature = "test_build")]
214 pub fn is_valid(&self) -> bool {
215 match self {
216 Self(Finite {
217 precision,
218 significand,
219 exponent,
220 ..
221 }) => {
222 if *precision == 0
223 || !significand.is_valid()
224 || *exponent > Self::MAX_EXPONENT
225 || *exponent < Self::MIN_EXPONENT
226 {
227 return false;
228 }
229 let bits = significand.significant_bits();
230 bits != 0
231 && bits.divisible_by_power_of_2(Limb::LOG_WIDTH)
232 && *precision <= bits
233 && bits - precision < Limb::WIDTH
234 && significand.divisible_by_power_of_2(bits - precision)
235 }
236 _ => true,
237 }
238 }
239}
240
241/// `ComparableFloat` is a wrapper around a [`Float`], taking the [`Float`] by value.
242///
243/// `CompatableFloat` has different comparison behavior than [`Float`]. See the [`Float`]
244/// documentation for its comparison behavior, which is largely derived from the IEEE 754
245/// specification; the `ComparableFloat` behavior, on the other hand, is more mathematically
246/// well-behaved, and respects the principle that equality should be the finest equivalence
247/// relation: that is, that two equal objects should not be different in any way.
248///
249/// To be more specific: when a [`Float`] is wrapped in a `ComparableFloat`,
250/// - `NaN` is not equal to any other [`Float`], but equal to itself;
251/// - Positive and negative zero are not equal to each other;
252/// - Ordering is total. Negative zero is ordered to be smaller than positive zero, and `NaN` is
253/// arbitrarily ordered to be between the two zeros;
254/// - Two [`Float`]s with different precisions but representing the same value are unequal, and the
255/// one with the greater precision is ordered to be larger;
256/// - The hashing function is compatible with equality.
257///
258/// The analogous wrapper for primitive floats is
259/// [`NiceFloat`](malachite_base::num::float::NiceFloat). However,
260/// [`NiceFloat`](malachite_base::num::float::NiceFloat) also facilitates better string conversion,
261/// something that isn't necessary for [`Float`]s
262///
263/// `ComparableFloat` owns its float. This is useful in many cases, for example if you want to use
264/// [`Float`]s as keys in a hash map. In other situations, it is better to use
265/// [`ComparableFloatRef`], which only has a reference to its float.
266#[derive(Clone)]
267pub struct ComparableFloat(pub Float);
268
269/// `ComparableFloatRef` is a wrapper around a [`Float`], taking the [`Float`] be reference.
270///
271/// See the [`ComparableFloat`] documentation for details.
272#[derive(Clone)]
273pub struct ComparableFloatRef<'a>(pub &'a Float);
274
275impl ComparableFloat {
276 pub const fn as_ref(&self) -> ComparableFloatRef<'_> {
277 ComparableFloatRef(&self.0)
278 }
279}
280
281impl Deref for ComparableFloat {
282 type Target = Float;
283
284 /// Allows a [`ComparableFloat`] to dereference to a [`Float`].
285 ///
286 /// ```
287 /// use malachite_base::num::basic::traits::One;
288 /// use malachite_float::{ComparableFloat, Float};
289 ///
290 /// let x = ComparableFloat(Float::ONE);
291 /// assert_eq!(*x, Float::ONE);
292 /// ```
293 fn deref(&self) -> &Float {
294 &self.0
295 }
296}
297
298impl Deref for ComparableFloatRef<'_> {
299 type Target = Float;
300
301 /// Allows a [`ComparableFloatRef`] to dereference to a [`Float`].
302 ///
303 /// ```
304 /// use malachite_base::num::basic::traits::One;
305 /// use malachite_float::{ComparableFloatRef, Float};
306 ///
307 /// let x = Float::ONE;
308 /// let y = ComparableFloatRef(&x);
309 /// assert_eq!(*y, Float::ONE);
310 /// ```
311 fn deref(&self) -> &Float {
312 self.0
313 }
314}
315
316#[allow(clippy::type_repetition_in_bounds)]
317#[doc(hidden)]
318pub fn emulate_float_to_float_fn<T: PrimitiveFloat, F: Fn(Float, u64) -> (Float, Ordering)>(
319 f: F,
320 x: T,
321) -> T
322where
323 Float: From<T> + PartialOrd<T>,
324 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
325{
326 let x = Float::from(x);
327 let (mut result, o) = f(x.clone(), T::MANTISSA_WIDTH + 1);
328 if !result.is_normal() {
329 return T::exact_from(&result);
330 }
331 let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
332 if e < T::MIN_NORMAL_EXPONENT {
333 if e < T::MIN_EXPONENT {
334 let rm =
335 if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
336 let down = if result > T::ZERO { Less } else { Greater };
337 if o == down { Up } else { Down }
338 } else {
339 Nearest
340 };
341 return T::rounding_from(&result, rm).0;
342 }
343 result = f(x, T::max_precision_for_sci_exponent(e)).0;
344 }
345 if result > T::MAX_FINITE {
346 T::INFINITY
347 } else if result < -T::MAX_FINITE {
348 T::NEGATIVE_INFINITY
349 } else {
350 T::exact_from(&result)
351 }
352}
353
354#[allow(clippy::type_repetition_in_bounds)]
355#[doc(hidden)]
356pub fn emulate_float_float_to_float_fn<
357 T: PrimitiveFloat,
358 F: Fn(Float, Float, u64) -> (Float, Ordering),
359>(
360 f: F,
361 x: T,
362 y: T,
363) -> T
364where
365 Float: From<T> + PartialOrd<T>,
366 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
367{
368 let x = Float::from(x);
369 let y = Float::from(y);
370 let (mut result, o) = f(x.clone(), y.clone(), T::MANTISSA_WIDTH + 1);
371 if !result.is_normal() {
372 return T::exact_from(&result);
373 }
374 let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
375 if e < T::MIN_NORMAL_EXPONENT {
376 if e < T::MIN_EXPONENT {
377 let rm =
378 if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
379 let down = if result > T::ZERO { Less } else { Greater };
380 if o == down { Up } else { Down }
381 } else {
382 Nearest
383 };
384 return T::rounding_from(&result, rm).0;
385 }
386 result = f(x, y, T::max_precision_for_sci_exponent(e)).0;
387 }
388 if result > T::MAX_FINITE {
389 T::INFINITY
390 } else if result < -T::MAX_FINITE {
391 T::NEGATIVE_INFINITY
392 } else {
393 T::exact_from(&result)
394 }
395}
396
397#[allow(clippy::type_repetition_in_bounds)]
398#[doc(hidden)]
399pub fn emulate_rational_to_float_fn<T: PrimitiveFloat, F: Fn(&Rational, u64) -> (Float, Ordering)>(
400 f: F,
401 x: &Rational,
402) -> T
403where
404 Float: PartialOrd<T>,
405 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
406{
407 let (mut result, o) = f(x, T::MANTISSA_WIDTH + 1);
408 if !result.is_normal() {
409 return T::exact_from(&result);
410 }
411 let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
412 if e < T::MIN_NORMAL_EXPONENT {
413 if e < T::MIN_EXPONENT {
414 let rm =
415 if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
416 let down = if result > T::ZERO { Less } else { Greater };
417 if o == down { Up } else { Down }
418 } else {
419 Nearest
420 };
421 return T::rounding_from(&result, rm).0;
422 }
423 result = f(x, T::max_precision_for_sci_exponent(e)).0;
424 }
425 if result > T::MAX_FINITE {
426 T::INFINITY
427 } else if result < -T::MAX_FINITE {
428 T::NEGATIVE_INFINITY
429 } else {
430 T::exact_from(&result)
431 }
432}
433
434#[allow(clippy::type_repetition_in_bounds)]
435#[doc(hidden)]
436pub fn emulate_rational_rational_to_float_fn<
437 T: PrimitiveFloat,
438 F: Fn(&Rational, &Rational, u64) -> (Float, Ordering),
439>(
440 f: F,
441 x: &Rational,
442 y: &Rational,
443) -> T
444where
445 Float: PartialOrd<T>,
446 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
447{
448 let (mut result, o) = f(x, y, T::MANTISSA_WIDTH + 1);
449 if !result.is_normal() {
450 return T::exact_from(&result);
451 }
452 let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
453 if e < T::MIN_NORMAL_EXPONENT {
454 if e < T::MIN_EXPONENT {
455 let rm =
456 if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
457 let down = if result > T::ZERO { Less } else { Greater };
458 if o == down { Up } else { Down }
459 } else {
460 Nearest
461 };
462 return T::rounding_from(&result, rm).0;
463 }
464 result = f(x, y, T::max_precision_for_sci_exponent(e)).0;
465 }
466 if result > T::MAX_FINITE {
467 T::INFINITY
468 } else if result < -T::MAX_FINITE {
469 T::NEGATIVE_INFINITY
470 } else {
471 T::exact_from(&result)
472 }
473}
474
475#[allow(clippy::type_repetition_in_bounds)]
476#[doc(hidden)]
477pub fn emulate_rational_float_to_float_fn<
478 T: PrimitiveFloat,
479 F: Fn(&Rational, Float, u64) -> (Float, Ordering),
480>(
481 f: F,
482 x: &Rational,
483 base: T,
484) -> T
485where
486 Float: From<T> + PartialOrd<T>,
487 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
488{
489 let base = Float::from(base);
490 let (mut result, o) = f(x, base.clone(), T::MANTISSA_WIDTH + 1);
491 if !result.is_normal() {
492 return T::exact_from(&result);
493 }
494 let e = i64::from(<&Float as SciMantissaAndExponent<Float, i32, _>>::sci_exponent(&result));
495 if e < T::MIN_NORMAL_EXPONENT {
496 if e < T::MIN_EXPONENT {
497 let rm =
498 if e == T::MIN_EXPONENT - 1 && result.significand_ref().unwrap().is_power_of_2() {
499 let down = if result > T::ZERO { Less } else { Greater };
500 if o == down { Up } else { Down }
501 } else {
502 Nearest
503 };
504 return T::rounding_from(&result, rm).0;
505 }
506 result = f(x, base, T::max_precision_for_sci_exponent(e)).0;
507 }
508 if result > T::MAX_FINITE {
509 T::INFINITY
510 } else if result < -T::MAX_FINITE {
511 T::NEGATIVE_INFINITY
512 } else {
513 T::exact_from(&result)
514 }
515}
516
517/// Given the `(Float, Ordering)` result of an operation, determines whether an overflow occurred.
518///
519/// We're defining an overflow to occur whenever the actual result is outside the representable
520/// finite range, and is rounded to either infinity or to the maximum or minimum representable
521/// finite value. An overflow can present itself in four ways:
522/// - The result is $\infty$ and the `Ordering` is `Greater`
523/// - The result is $-\infty$ and the `Ordering` is `Less`
524/// - The result is the largest finite value (of any `Float` with its precision) and the `Ordering`
525/// is `Less`
526/// - The result is the smallest (most negative) finite value (of any `Float` with its precision)
527/// and the `Ordering` is `Greater`
528///
529/// # Worst-case complexity
530/// $T(n) = O(n)$
531///
532/// $M(n) = O(1)$
533///
534/// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
535///
536/// # Examples
537/// ```
538/// use malachite_base::num::basic::traits::{Infinity, NegativeInfinity, One};
539/// use malachite_float::{test_overflow, Float};
540/// use std::cmp::Ordering::*;
541///
542/// assert!(test_overflow(&Float::INFINITY, Greater));
543/// assert!(test_overflow(&Float::NEGATIVE_INFINITY, Less));
544/// assert!(test_overflow(&Float::max_finite_value_with_prec(10), Less));
545/// assert!(test_overflow(
546/// &-Float::max_finite_value_with_prec(10),
547/// Greater
548/// ));
549///
550/// assert!(!test_overflow(&Float::INFINITY, Equal));
551/// assert!(!test_overflow(&Float::ONE, Less));
552/// ```
553pub fn test_overflow(result: &Float, o: Ordering) -> bool {
554 if o == Equal {
555 return false;
556 }
557 *result == Float::INFINITY && o == Greater
558 || *result == Float::NEGATIVE_INFINITY && o == Less
559 || *result > 0u32 && result.abs_is_max_finite_value_with_prec() && o == Less
560 || *result < 0u32 && result.abs_is_max_finite_value_with_prec() && o == Greater
561}
562
563/// Given the `(Float, Ordering)` result of an operation, determines whether an underflow occurred.
564///
565/// We're defining an underflow to occur whenever the actual result is outside the representable
566/// finite range, and is rounded to zero, to the minimum positive value, or to the maximum negative
567/// value. An underflow can present itself in four ways:
568/// - The result is $0.0$ or $-0.0$ and the `Ordering` is `Less`
569/// - The result is $0.0$ or $-0.0$ and the `Ordering` is `Greater`
570/// - The result is the smallest positive value and the `Ordering` is `Greater`
571/// - The result is the largest (least negative) negative value and the `Ordering` is `Less`
572///
573/// # Worst-case complexity
574/// $T(n) = O(n)$
575///
576/// $M(n) = O(1)$
577///
578/// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
579///
580/// # Examples
581/// ```
582/// use malachite_base::num::basic::traits::{One, Zero};
583/// use malachite_float::{test_underflow, Float};
584/// use std::cmp::Ordering::*;
585///
586/// assert!(test_underflow(&Float::ZERO, Less));
587/// assert!(test_underflow(&Float::ZERO, Greater));
588/// assert!(test_underflow(&Float::min_positive_value_prec(10), Greater));
589/// assert!(test_underflow(&-Float::min_positive_value_prec(10), Less));
590///
591/// assert!(!test_underflow(&Float::ZERO, Equal));
592/// assert!(!test_underflow(&Float::ONE, Less));
593/// ```
594pub fn test_underflow(result: &Float, o: Ordering) -> bool {
595 if o == Equal {
596 return false;
597 }
598 *result == 0u32
599 || *result > 0u32 && result.abs_is_min_positive_value() && o == Greater
600 || *result < 0u32 && result.abs_is_min_positive_value() && o == Less
601}
602
603/// Traits for arithmetic.
604pub mod arithmetic;
605#[macro_use]
606/// Basic traits for working with [`Float`]s.
607pub mod basic;
608/// Traits for comparing [`Float`]s for equality or order.
609pub mod comparison;
610/// Functions that produce [`Float`] approximations of mathematical constants, using a given
611/// precision and rounding mode.
612pub mod constants;
613/// Traits for converting to and from [`Float`]s, including converting [`Float`]s to and from
614/// strings.
615pub mod conversion;
616/// Iterators that generate [`Float`]s without repetition.
617pub mod exhaustive;
618#[cfg(feature = "random")]
619/// Iterators that generate [`Float`]s randomly.
620pub mod random;
621
622#[cfg(feature = "test_build")]
623pub mod test_util;