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}