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}