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