Skip to main content

malachite_float/float/basic/
ulp.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::InnerFloat::Finite;
10use crate::{Float, significand_bits};
11use malachite_base::num::arithmetic::traits::{NegAssign, PowerOf2};
12use malachite_base::num::basic::traits::{Infinity, Zero};
13use malachite_base::num::conversion::traits::WrappingFrom;
14use malachite_base::num::logic::traits::{BitAccess, SignificantBits};
15use malachite_nz::natural::{Natural, bit_to_limb_count_floor};
16use malachite_nz::platform::Limb;
17
18impl Float {
19    /// Gets a [`Float`]'s ulp (unit in last place, or unit of least precision).
20    ///
21    /// If the [`Float`] is positive, its ulp is the distance to the next-largest [`Float`] with the
22    /// same precision; if it is negative, the next-smallest. (This definition works even if the
23    /// [`Float`] is the largest in its binade. If the [`Float`] is the largest in its binade and
24    /// has the maximum exponent, we can define its ulp to be the distance to the next-smallest
25    /// [`Float`] with the same precision if positive, and to the next-largest [`Float`] with the
26    /// same precision if negative.)
27    ///
28    /// If the [`Float`] is NaN, infinite, or zero, then `None` is returned.
29    ///
30    /// This function does not overflow or underflow, technically. But it is possible that a
31    /// [`Float`]'s ulp is too small to represent, for example if the [`Float`] has the minimum
32    /// exponent and its precision is greater than 1, or if the precision is extremely large in
33    /// general. In such cases, `None` is returned.
34    ///
35    /// $$
36    /// f(\text{NaN}) = f(\pm\infty) = f(\pm 0.0) = \text{None},
37    /// $$
38    ///
39    /// and, if $x$ is finite and nonzero,
40    ///
41    /// $$
42    /// f(x) = \operatorname{Some}(2^{\lfloor \log_2 |x| \rfloor-p+1}),
43    /// $$
44    /// where $p$ is the precision of $x$.
45    ///
46    /// # Worst-case complexity
47    /// $T(n) = O(n)$
48    ///
49    /// $M(n) = O(n)$
50    ///
51    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
52    ///
53    /// # Examples
54    /// ```
55    /// use malachite_base::num::arithmetic::traits::PowerOf2;
56    /// use malachite_base::num::basic::traits::{Infinity, NaN, NegativeOne, One, Zero};
57    /// use malachite_float::Float;
58    ///
59    /// assert_eq!(Float::NAN.ulp(), None);
60    /// assert_eq!(Float::INFINITY.ulp(), None);
61    /// assert_eq!(Float::ZERO.ulp(), None);
62    ///
63    /// let s = Float::ONE.ulp().map(|x| x.to_string());
64    /// assert_eq!(s.as_ref().map(|s| s.as_str()), Some("1.0"));
65    ///
66    /// let s = Float::one_prec(100).ulp().map(|x| x.to_string());
67    /// assert_eq!(s.as_ref().map(|s| s.as_str()), Some("1.6e-30"));
68    ///
69    /// let s = Float::from(std::f64::consts::PI)
70    ///     .ulp()
71    ///     .map(|x| x.to_string());
72    /// assert_eq!(s.as_ref().map(|s| s.as_str()), Some("3.6e-15"));
73    ///
74    /// let s = Float::power_of_2(100u64).ulp().map(|x| x.to_string());
75    /// assert_eq!(s.as_ref().map(|s| s.as_str()), Some("1.3e30"));
76    ///
77    /// let s = Float::power_of_2(-100i64).ulp().map(|x| x.to_string());
78    /// assert_eq!(s.as_ref().map(|s| s.as_str()), Some("7.9e-31"));
79    ///
80    /// let s = Float::NEGATIVE_ONE.ulp().map(|x| x.to_string());
81    /// assert_eq!(s.as_ref().map(|s| s.as_str()), Some("1.0"));
82    /// ```
83    pub fn ulp(&self) -> Option<Self> {
84        match self {
85            Self(Finite {
86                exponent,
87                precision,
88                ..
89            }) => {
90                let ulp_exponent =
91                    i64::from(*exponent).checked_sub(i64::try_from(*precision).ok()?)?;
92                if i32::try_from(ulp_exponent).ok()? >= Self::MIN_EXPONENT_MINUS_1 {
93                    Some(Self::power_of_2(ulp_exponent))
94                } else {
95                    None
96                }
97            }
98            _ => None,
99        }
100    }
101
102    /// Steps a [`Float`] up to the closest larger [`Float`] with the same precision. This matches
103    /// the IEEE 754 `nextUp` operation and MPFR's `mpfr_nextabove`, except that this function
104    /// panics on NaN, infinities, and zeros rather than handling them.
105    ///
106    /// For most values this adds one ulp (see [`Float::ulp`]). If the [`Float`] is positive and is
107    /// the largest [`Float`] in its binade with its precision, then
108    /// - If its exponent is not the maximum exponent, it will become the power of 2 at the bottom
109    ///   of the next-higher binade (still a step of one ulp);
110    /// - If its exponent is the maximum exponent, it will become $\infty$.
111    ///
112    /// If the [`Float`] is negative and is closer to zero than any other [`Float`] in its binade
113    /// with its precision (that is, its significand is a power of 2), then
114    /// - If its exponent is not the minimum exponent, it will move half an ulp toward zero, to the
115    ///   largest-magnitude [`Float`] in the next-lower binade with its precision (at precision 1
116    ///   the next power of 2, at higher precisions the value with an all-ones significand);
117    /// - If its exponent is the minimum exponent, it will become negative zero.
118    ///
119    /// # Worst-case complexity
120    /// $T(n) = O(n)$
121    ///
122    /// $M(n) = O(n)$
123    ///
124    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
125    ///
126    /// # Panics
127    /// Panics if `self` is NaN, infinite, or zero.
128    ///
129    /// # Examples
130    /// ```
131    /// use malachite_base::num::arithmetic::traits::PowerOf2;
132    /// use malachite_base::num::basic::traits::{NegativeOne, One};
133    /// use malachite_float::Float;
134    ///
135    /// let mut x = Float::ONE;
136    /// assert_eq!(x.to_string(), "1.0");
137    /// x.increment();
138    /// assert_eq!(x.to_string(), "2.0");
139    ///
140    /// let mut x = Float::one_prec(100);
141    /// assert_eq!(x.to_string(), "1.0000000000000000000000000000000");
142    /// x.increment();
143    /// assert_eq!(x.to_string(), "1.0000000000000000000000000000016");
144    ///
145    /// let mut x = Float::from(std::f64::consts::PI);
146    /// assert_eq!(x.to_string(), "3.1415926535897931");
147    /// x.increment();
148    /// assert_eq!(x.to_string(), "3.1415926535897967");
149    ///
150    /// let mut x = Float::power_of_2(100u64);
151    /// assert_eq!(x.to_string(), "1.3e30");
152    /// x.increment();
153    /// assert_eq!(x.to_string(), "2.5e30");
154    ///
155    /// let mut x = Float::power_of_2(-100i64);
156    /// assert_eq!(x.to_string(), "7.9e-31");
157    /// x.increment();
158    /// assert_eq!(x.to_string(), "1.6e-30");
159    ///
160    /// let mut x = Float::NEGATIVE_ONE;
161    /// assert_eq!(x.to_string(), "-1.0");
162    /// x.increment();
163    /// assert_eq!(x.to_string(), "-0.50");
164    /// ```
165    pub fn increment(&mut self) {
166        if self.is_sign_negative() {
167            self.neg_assign();
168            self.decrement();
169            self.neg_assign();
170        } else if let Self(Finite {
171            exponent,
172            precision,
173            significand,
174            ..
175        }) = self
176        {
177            let ulp = Limb::power_of_2(significand_bits(significand) - *precision);
178            let limb_count = significand.limb_count();
179            significand.add_assign_at_limb(
180                usize::wrapping_from(limb_count) - 1 - bit_to_limb_count_floor(*precision - 1),
181                ulp,
182            );
183            if significand.limb_count() > limb_count {
184                // The value was the largest in its binade with its precision, so stepping up lands
185                // on the power of 2 at the bottom of the next-higher binade, which is representable
186                // with the same precision.
187                if *exponent == Self::MAX_EXPONENT {
188                    *self = Self::INFINITY;
189                    return;
190                }
191                *significand >>= 1;
192                *exponent += 1;
193            }
194        } else {
195            panic!("Cannot increment float is non-finite or zero");
196        }
197    }
198
199    /// Steps a [`Float`] down to the closest smaller [`Float`] with the same precision. This
200    /// matches the IEEE 754 `nextDown` operation and MPFR's `mpfr_nextbelow`, except that this
201    /// function panics on NaN, infinities, and zeros rather than handling them.
202    ///
203    /// For most values this subtracts one ulp (see [`Float::ulp`]). If the [`Float`] is negative
204    /// and is the largest-magnitude [`Float`] in its binade with its precision, then
205    /// - If its exponent is not the maximum exponent, it will become the negative power of 2 at the
206    ///   bottom of the next-higher binade (still a step of one ulp);
207    /// - If its exponent is the maximum exponent, it will become $-\infty$.
208    ///
209    /// If the [`Float`] is positive and is smaller than any other [`Float`] in its binade with its
210    /// precision (that is, its significand is a power of 2), then
211    /// - If its exponent is not the minimum exponent, it will move half an ulp toward zero, to the
212    ///   largest [`Float`] in the next-lower binade with its precision (at precision 1 the next
213    ///   power of 2, at higher precisions the value with an all-ones significand);
214    /// - If its exponent is the minimum exponent, it will become positive zero.
215    ///
216    /// # Worst-case complexity
217    /// $T(n) = O(n)$
218    ///
219    /// $M(n) = O(n)$
220    ///
221    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
222    ///
223    /// # Panics
224    /// Panics if `self` is NaN, infinite, or zero.
225    ///
226    /// # Examples
227    /// ```
228    /// use malachite_base::num::arithmetic::traits::PowerOf2;
229    /// use malachite_base::num::basic::traits::{NegativeOne, One};
230    /// use malachite_float::Float;
231    ///
232    /// let mut x = Float::ONE;
233    /// assert_eq!(x.to_string(), "1.0");
234    /// x.decrement();
235    /// assert_eq!(x.to_string(), "0.50");
236    ///
237    /// let mut x = Float::one_prec(100);
238    /// assert_eq!(x.to_string(), "1.0000000000000000000000000000000");
239    /// x.decrement();
240    /// assert_eq!(x.to_string(), "0.99999999999999999999999999999921");
241    ///
242    /// let mut x = Float::from(std::f64::consts::PI);
243    /// assert_eq!(x.to_string(), "3.1415926535897931");
244    /// x.decrement();
245    /// assert_eq!(x.to_string(), "3.1415926535897896");
246    ///
247    /// let mut x = Float::power_of_2(100u64);
248    /// assert_eq!(x.to_string(), "1.3e30");
249    /// x.decrement();
250    /// assert_eq!(x.to_string(), "6.3e29");
251    ///
252    /// let mut x = Float::power_of_2(-100i64);
253    /// assert_eq!(x.to_string(), "7.9e-31");
254    /// x.decrement();
255    /// assert_eq!(x.to_string(), "3.9e-31");
256    ///
257    /// let mut x = Float::NEGATIVE_ONE;
258    /// assert_eq!(x.to_string(), "-1.0");
259    /// x.decrement();
260    /// assert_eq!(x.to_string(), "-2.0");
261    /// ```
262    pub fn decrement(&mut self) {
263        if self.is_sign_negative() {
264            self.neg_assign();
265            self.increment();
266            self.neg_assign();
267        } else if let Self(Finite {
268            exponent,
269            precision,
270            significand,
271            ..
272        }) = self
273        {
274            let bits = significand_bits(significand);
275            let ulp = Limb::power_of_2(bits - *precision);
276            significand.sub_assign_at_limb(
277                usize::wrapping_from(significand.limb_count())
278                    - 1
279                    - bit_to_limb_count_floor(*precision - 1),
280                ulp,
281            );
282            if *significand == 0u32 {
283                // The value was a power of 2 with precision 1, so stepping down lands on the next
284                // power of 2, unless that is out of range.
285                if *exponent == Self::MIN_EXPONENT {
286                    *self = Self::ZERO;
287                } else {
288                    *significand = Natural::power_of_2(bits - 1);
289                    *exponent -= 1;
290                }
291            } else if significand.significant_bits() < bits {
292                // The value was a power of 2 with precision greater than 1, so stepping down
293                // crosses into the next-lower binade, where the closest value is half an ulp away
294                // and has an all-ones significand with the same precision — unless the lower
295                // binade is out of range.
296                if *exponent == Self::MIN_EXPONENT {
297                    *self = Self::ZERO;
298                    return;
299                }
300                significand.set_bit(bits - 1);
301                *exponent -= 1;
302            }
303        } else {
304            panic!("Cannot decrement float that is non-finite or zero");
305        }
306    }
307}