malachite_float/arithmetic/
is_power_of_2.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::Float;
10use crate::InnerFloat::Finite;
11use malachite_base::num::arithmetic::traits::IsPowerOf2;
12use malachite_base::num::basic::integers::PrimitiveInt;
13use malachite_base::num::basic::signeds::PrimitiveSigned;
14use malachite_nz::platform::Limb;
15
16const HIGH_BIT: Limb = 1 << (Limb::WIDTH - 1);
17
18impl IsPowerOf2 for Float {
19    /// Determines whether a [`Float`] is an integer power of 2.
20    ///
21    /// $f(x) = (\exists n \in \Z : 2^n = x)$.
22    ///
23    /// [`Float`]s that are NaN, infinite, or zero are not powers of 2.
24    ///
25    /// # Worst-case complexity
26    /// $T(n) = O(n)$
27    ///
28    /// $M(n) = O(1)$
29    ///
30    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
31    ///
32    /// # Examples
33    /// ```
34    /// use malachite_base::num::arithmetic::traits::IsPowerOf2;
35    /// use malachite_base::num::basic::traits::{NaN, One, OneHalf, Two};
36    /// use malachite_float::Float;
37    ///
38    /// assert_eq!(Float::NAN.is_power_of_2(), false);
39    ///
40    /// assert_eq!(Float::ONE.is_power_of_2(), true);
41    /// assert_eq!(Float::TWO.is_power_of_2(), true);
42    /// assert_eq!(Float::ONE_HALF.is_power_of_2(), true);
43    /// assert_eq!(Float::from(1024).is_power_of_2(), true);
44    ///
45    /// assert_eq!(Float::from(3).is_power_of_2(), false);
46    /// assert_eq!(Float::from(1025).is_power_of_2(), false);
47    /// assert_eq!(Float::from(0.1f64).is_power_of_2(), false);
48    /// ```
49    fn is_power_of_2(&self) -> bool {
50        match self {
51            Self(Finite {
52                sign: true,
53                significand,
54                ..
55            }) => {
56                let mut first = true;
57                for x in significand.limbs().rev() {
58                    if first {
59                        if x != HIGH_BIT {
60                            return false;
61                        }
62                        first = false;
63                    } else if x != 0 {
64                        return false;
65                    }
66                }
67                true
68            }
69            _ => false,
70        }
71    }
72}
73
74pub(crate) fn abs_is_power_of_2(x: &Float) -> bool {
75    match x {
76        Float(Finite { significand, .. }) => {
77            let mut first = true;
78            for x in significand.limbs().rev() {
79                if first {
80                    if x != HIGH_BIT {
81                        return false;
82                    }
83                    first = false;
84                } else if x != 0 {
85                    return false;
86                }
87            }
88            true
89        }
90        _ => false,
91    }
92}
93
94pub(crate) fn float_is_signed_min<T: PrimitiveSigned>(f: &Float) -> bool {
95    match f {
96        Float(Finite {
97            sign: false,
98            exponent,
99            significand,
100            ..
101        }) => {
102            if *exponent != T::WIDTH as i32 {
103                return false;
104            }
105            let mut first = true;
106            for x in significand.limbs().rev() {
107                if first {
108                    if x != HIGH_BIT {
109                        return false;
110                    }
111                    first = false;
112                } else if x != 0 {
113                    return false;
114                }
115            }
116            true
117        }
118        _ => false,
119    }
120}