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}