Skip to main content

a/math/numbers/
sign.rs

1//! The sign of a number: `-a` with [`Neg`], [`Number::abs`], [`Number::signum`],
2//! [`Number::is_zero`] and [`Number::is_positive`].
3
4use super::add::significant_len;
5use super::{ByteOrder, Number};
6use core::ops::Neg;
7
8impl Number {
9    /// Returns whether the number is zero: whether every byte of its magnitude is zero, or it has
10    /// none.
11    ///
12    /// A number in the shortest form costs one read of its top byte.
13    ///
14    /// # Examples
15    ///
16    /// ```
17    /// use a::math::numbers::{ByteOrder, Number};
18    ///
19    /// assert!(Number::new_from_u8(0, ByteOrder::BigEndian).is_zero());
20    /// assert!(Number::new(Vec::new(), ByteOrder::LittleEndian).is_zero());
21    /// assert!(!Number::new_from_i8(-1, ByteOrder::BigEndian).is_zero());
22    /// ```
23    #[inline]
24    pub fn is_zero(&self) -> bool {
25        self.significant() == 0
26    }
27
28    /// Returns whether the number is above zero.
29    ///
30    /// # Examples
31    ///
32    /// ```
33    /// use a::math::numbers::{ByteOrder, Number};
34    ///
35    /// assert!(Number::new_from_i8(1, ByteOrder::BigEndian).is_positive());
36    /// assert!(!Number::new_from_i8(0, ByteOrder::BigEndian).is_positive());
37    /// assert!(!Number::new_from_i8(-1, ByteOrder::BigEndian).is_positive());
38    /// ```
39    #[inline]
40    pub fn is_positive(&self) -> bool {
41        !self.negative && !self.is_zero()
42    }
43
44    /// Returns the absolute value of the number, in its byte order and in the shortest form, in
45    /// one new vector of exactly its length.
46    ///
47    /// # Examples
48    ///
49    /// ```
50    /// use a::math::numbers::{ByteOrder, Number};
51    ///
52    /// let n = Number::new_from_i32(-1000, ByteOrder::BigEndian).abs();
53    /// assert_eq!(n, 1000);
54    /// assert!(!n.is_negative());
55    /// ```
56    #[inline]
57    pub fn abs(&self) -> Number {
58        self.with_sign(false)
59    }
60
61    /// Returns the sign of the number as a number, in its byte order: -1 below zero, 0 for zero
62    /// and 1 above, as [`i32::signum`] does.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use a::math::numbers::{ByteOrder, Number};
68    ///
69    /// assert_eq!(Number::new_from_i32(-1000, ByteOrder::BigEndian).signum(), -1);
70    /// assert_eq!(Number::new_from_i32(0, ByteOrder::BigEndian).signum(), 0);
71    /// assert_eq!(Number::new_from_i32(1000, ByteOrder::LittleEndian).signum(), 1);
72    /// ```
73    #[inline]
74    pub fn signum(&self) -> Number {
75        let zero = self.is_zero();
76        Number {
77            value: vec![u8::from(!zero)],
78            negative: self.negative && !zero,
79            byte_order: self.byte_order,
80        }
81    }
82
83    /// The length of the magnitude without the zero bytes above its most significant non-zero
84    /// byte.
85    #[inline(always)]
86    pub(super) fn significant(&self) -> usize {
87        if self.byte_order == ByteOrder::BigEndian {
88            significant_len::<true>(&self.value)
89        } else {
90            significant_len::<false>(&self.value)
91        }
92    }
93
94    /// The magnitude of the number with the sign `negative` (which zero does not keep), in its
95    /// byte order and in the shortest form, in one new vector of exactly its length.
96    #[inline]
97    fn with_sign(&self, negative: bool) -> Number {
98        let s = self.significant();
99        let value = if s == 0 {
100            vec![0]
101        } else if self.byte_order == ByteOrder::BigEndian {
102            self.value[self.value.len() - s..].to_vec()
103        } else {
104            self.value[..s].to_vec()
105        };
106        Number {
107            value,
108            negative: negative && s != 0,
109            byte_order: self.byte_order,
110        }
111    }
112}
113
114/// Trims the magnitude of `n` to the shortest form, in place: drops the zero bytes above its most
115/// significant non-zero byte, and makes zero `[0]` and not negative.
116#[inline]
117pub(super) fn trim(n: &mut Number) {
118    let s = n.significant();
119    let len = n.value.len();
120    if s == 0 {
121        n.value.clear();
122        n.value.push(0);
123        n.negative = false;
124    } else if s != len {
125        if n.byte_order == ByteOrder::BigEndian {
126            n.value.drain(..len - s);
127        } else {
128            n.value.truncate(s);
129        }
130    }
131}
132
133impl Neg for Number {
134    type Output = Number;
135
136    /// Returns `-self`: the same magnitude with the other sign, in the shortest form, in the
137    /// vector of `self`; zero stays zero, never negative.
138    ///
139    /// # Examples
140    ///
141    /// ```
142    /// use a::math::numbers::{ByteOrder, Number};
143    ///
144    /// let n = -Number::new_from_i32(1000, ByteOrder::BigEndian);
145    /// assert_eq!(n, -1000);
146    /// assert_eq!(-n, 1000);
147    /// assert!(!(-Number::new_from_u8(0, ByteOrder::BigEndian)).is_negative());
148    /// ```
149    #[inline]
150    fn neg(mut self) -> Number {
151        trim(&mut self);
152        self.negative = !self.negative && self.value != [0];
153        self
154    }
155}
156
157impl Neg for &Number {
158    type Output = Number;
159
160    /// Returns `-self`: the same magnitude with the other sign, in the byte order of `self` and in
161    /// the shortest form, in one new vector of exactly its length; zero stays zero.
162    #[inline]
163    fn neg(self) -> Number {
164        self.with_sign(!self.negative)
165    }
166}