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}