a/math/numbers/sub.rs
1//! Subtraction of [`Number`]s: `-` and `-=`, with either operand owned or borrowed.
2//!
3//! `a - b` is `a + (-b)`, and it is computed as that sum, by the addition and with everything it
4//! does: the paths in registers for operands of at most 16 and 64 bytes, the plan of the exact
5//! length, and the kernels in inline assembly on `x86_64` (`sbb` and `adc` chains through the
6//! carry flag) and on 64-bit little-endian `aarch64` (`sbcs` and `adcs`, in several interleaved
7//! chains for long operands), portable Rust elsewhere. So a difference costs what a sum of the
8//! same magnitudes does, and the operators keep the promises of `+` and `+=`: the difference is
9//! exact, in the shortest form and in the byte order of the left operand, and it is built in
10//! the vector of an operand taken by value, or of the target of `-=`, when that has room for it
11//! (the left operand's first), and otherwise in one new vector of exactly its length. The
12//! magnitudes are subtracted when the signs of `a` and `-b` differ, as for `5 - 3`, and added
13//! when they agree, as for `5 - (-3)`.
14//!
15//! The sign of `b` is turned over without changing the code of the addition:
16//!
17//! - Operands of at most 64 bytes take the paths of the addition in registers, inlined up to 16
18//! bytes and out of line from there, with the sign of `b` turned over as it is read into a
19//! register.
20//! - An owned `b` has its sign turned over in place, and is then added.
21//! - `a -= &b` on longer operands cannot change `b`, so it turns over the sign of `a` instead:
22//! `a - b` is `-(-a + b)`. The sign of `a` is turned over, `b` is added, and the sign of the
23//! sum is turned back, unless the sum is zero, which stays not negative. Only the sign of `a`
24//! goes through memory on its way to the addition, and it decides only branches, which the
25//! core predicts; the vectors of both operands are read where they are. The addition hands
26//! `a` back, so that the shorter paths, which end in calls, save no registers for it.
27//! - `&a - &b` on longer operands can change neither, so it adds to `a` a copy of the fields of
28//! `b` with the sign turned over, which shares the vector of `b` and is only read (see
29//! [`Negated`]). The addition reads the vector's address and length from that copy, a store
30//! and a load later than from `b` itself, which the allocation of the difference's vector
31//! hides; a long difference built in place, whose kernel starts before the plan is done, would
32//! wait for them.
33
34use super::Number;
35use super::add::{
36 Fallback, add_assign_ref, medium, medium_into, medium_new, ref_plus_ref, small, small_add_to,
37 small_number_of,
38};
39use core::marker::PhantomData;
40use core::mem::ManuallyDrop;
41use core::ops::{Deref, Sub, SubAssign};
42use core::ptr;
43
44impl Sub<&Number> for &Number {
45 type Output = Number;
46
47 /// Returns `self - rhs`, in the byte order of `self`, in the shortest form.
48 ///
49 /// The difference is built in one new vector of exactly its length (one byte for zero), the
50 /// only allocation; both operands are left as they were. The operands may have any signs,
51 /// byte orders and lengths, and need not be in the shortest form.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use a::math::numbers::{ByteOrder, Number};
57 ///
58 /// // 0x01_00 - 0x01_01 = -1, in the byte order of the left operand.
59 /// let a = Number::new_from_i32(0x0100, ByteOrder::BigEndian);
60 /// let b = Number::new_from_i32(0x0101, ByteOrder::LittleEndian);
61 /// let difference = &a - &b;
62 /// assert_eq!(difference.value, [1]);
63 /// assert!(difference.is_negative());
64 /// assert!(difference.byte_order() == ByteOrder::BigEndian);
65 ///
66 /// // A number minus itself is zero, one zero byte and not negative.
67 /// let zero = &a - &a;
68 /// assert_eq!(zero.value, [0]);
69 /// assert!(!zero.is_negative());
70 /// ```
71 fn sub(self, rhs: &Number) -> Number {
72 if small(self, rhs) {
73 return small_number_of(self, rhs, !rhs.negative);
74 }
75 if medium(self, rhs) {
76 return medium_new(self, rhs, !rhs.negative);
77 }
78 ref_plus_ref(self, &Negated::new(rhs))
79 }
80}
81
82impl Sub<&Number> for Number {
83 type Output = Number;
84
85 /// Returns `self - rhs`, in the byte order of `self`, in the shortest form, as
86 /// `self -= rhs` does.
87 ///
88 /// The difference is built in the vector of `self` when its capacity has room for it, which
89 /// allocates nothing, and otherwise in one new vector of exactly its length. `rhs` is left
90 /// as it was.
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use a::math::numbers::{ByteOrder, Number};
96 ///
97 /// let a = Number::new(vec![1, 0, 0], ByteOrder::BigEndian);
98 /// let pointer = a.value.as_ptr();
99 /// let one = Number::new_from_u8(1, ByteOrder::BigEndian);
100 ///
101 /// // 0x01_00_00 - 1 = 0xFF_FF, in the vector of `a`.
102 /// let difference = a - &one;
103 /// assert_eq!(difference.value, [0xFF, 0xFF]);
104 /// assert_eq!(difference.value.as_ptr(), pointer);
105 /// ```
106 fn sub(mut self, rhs: &Number) -> Number {
107 self -= rhs;
108 self
109 }
110}
111
112impl Sub<Number> for &Number {
113 type Output = Number;
114
115 /// Returns `self - rhs`, in the byte order of `self`, in the shortest form.
116 ///
117 /// The difference is built in the vector of `rhs` when its capacity has room for it, which
118 /// allocates nothing, also when `rhs` is in the other byte order; otherwise it gets one new
119 /// vector of exactly its length. `self` is left as it was.
120 ///
121 /// # Examples
122 ///
123 /// ```
124 /// use a::math::numbers::{ByteOrder, Number};
125 ///
126 /// let a = Number::new_from_u32(0x01_02_03, ByteOrder::BigEndian);
127 /// let mut value = Vec::with_capacity(3);
128 /// value.extend([0x10, 0x20]);
129 /// let b = Number::new(value, ByteOrder::LittleEndian);
130 /// let pointer = b.value.as_ptr();
131 ///
132 /// // 0x01_02_03 - 0x20_10 = 0xE1_F3, big-endian, in the vector of `b`.
133 /// let difference = &a - b;
134 /// assert_eq!(difference.value, [0xE1, 0xF3]);
135 /// assert_eq!(difference.value.as_ptr(), pointer);
136 /// ```
137 fn sub(self, mut rhs: Number) -> Number {
138 rhs.negative = !rhs.negative;
139 self + rhs
140 }
141}
142
143impl Sub<Number> for Number {
144 type Output = Number;
145
146 /// Returns `self - rhs`, in the byte order of `self`, in the shortest form, as
147 /// `self -= rhs` does.
148 ///
149 /// The difference is built in the vector of `self` when its capacity has room for it, or
150 /// else in the vector of `rhs` when that has room, also when `rhs` is in the other byte
151 /// order, either of which allocates nothing; otherwise it gets one new vector of exactly
152 /// its length.
153 ///
154 /// # Examples
155 ///
156 /// ```
157 /// use a::math::numbers::{ByteOrder, Number};
158 ///
159 /// // 0x01_00 - 0x02_FF = -0x01_FF.
160 /// let a = Number::new_from_i32(0x0100, ByteOrder::LittleEndian);
161 /// let b = Number::new_from_i32(0x02FF, ByteOrder::BigEndian);
162 /// let difference = a - b;
163 /// assert_eq!(difference.value, [0xFF, 0x01]);
164 /// assert!(difference.is_negative());
165 /// ```
166 fn sub(mut self, rhs: Number) -> Number {
167 self -= rhs;
168 self
169 }
170}
171
172impl SubAssign<&Number> for Number {
173 /// Subtracts `rhs` from `self`, keeping the byte order of `self`, in the shortest form.
174 ///
175 /// The difference is built in the vector of `self` when its capacity has room for it, which
176 /// allocates nothing, and otherwise in one new vector of exactly its length, which replaces
177 /// it. `rhs` is left as it was.
178 ///
179 /// # Examples
180 ///
181 /// ```
182 /// use a::math::numbers::{ByteOrder, Number};
183 ///
184 /// let mut n = Number::new_from_u16(0x0200, ByteOrder::LittleEndian);
185 /// n -= &Number::new_from_u8(1, ByteOrder::BigEndian);
186 /// assert_eq!(n.value, [0xFF, 0x01]);
187 /// n -= &Number::new_from_u16(0x0200, ByteOrder::BigEndian);
188 /// assert_eq!(n.value, [1]);
189 /// assert!(n.is_negative());
190 /// ```
191 #[inline]
192 fn sub_assign(&mut self, rhs: &Number) {
193 if small(self, rhs) {
194 small_add_to(self, rhs, !rhs.negative);
195 return;
196 }
197 if medium(self, rhs) {
198 let (a, b) = (ptr::from_mut(self), ptr::from_ref(rhs).cast_mut());
199 // SAFETY: both operands are valid and take the medium path, the difference goes to
200 // `a`, and `b` is only read.
201 unsafe { medium_into(a, b, !rhs.negative, a, Fallback::New) };
202 return;
203 }
204 // a - b = -(-a + b). A zero `a` turned negative is zero to the addition, and a zero sum
205 // is `[0]` and not negative, which it stays. The sign of the sum is turned back without
206 // a branch on it, a coin toss for random operands of the same length; the branch on the
207 // length is not, as a sum this long is one byte long only when its operands nearly
208 // cancel, and then only is its byte read, which may still be on its way to memory. The
209 // addition gives `self` back, so that no register keeps it across the call, and the
210 // shorter paths above, which end in calls, save none.
211 self.negative = !self.negative;
212 let a = add_assign_ref(self, rhs);
213 let zero = a.value.len() == 1 && a.value[0] == 0;
214 a.negative = !a.negative & !zero;
215 }
216}
217
218impl SubAssign<Number> for Number {
219 /// Subtracts `rhs` from `self`, keeping the byte order of `self`, in the shortest form.
220 ///
221 /// The difference is built in the vector of `self` when its capacity has room for it, or
222 /// else in the vector of `rhs` when that has room, also when `rhs` is in the other byte
223 /// order, either of which allocates nothing; otherwise it gets one new vector of exactly
224 /// its length.
225 ///
226 /// # Examples
227 ///
228 /// ```
229 /// use a::math::numbers::{ByteOrder, Number};
230 ///
231 /// // `n` has no room for 0xFF - (-1) = 0x01_00, but the vector of the right operand has.
232 /// let mut n = Number::new_from_u8(0xFF, ByteOrder::BigEndian);
233 /// let mut value = Vec::with_capacity(2);
234 /// value.push(1);
235 /// let minus_one = Number::new_signed(value, true, ByteOrder::BigEndian);
236 /// let pointer = minus_one.value.as_ptr();
237 /// n -= minus_one;
238 /// assert_eq!(n.value, [1, 0]);
239 /// assert_eq!(n.value.as_ptr(), pointer);
240 /// ```
241 #[inline]
242 fn sub_assign(&mut self, mut rhs: Number) {
243 rhs.negative = !rhs.negative;
244 *self += rhs;
245 }
246}
247
248/// A borrowed number with the opposite sign, for the addition: a copy of its fields that shares
249/// its vector, which it lets be read only and never drops.
250pub(super) struct Negated<'a> {
251 number: ManuallyDrop<Number>,
252 borrowed: PhantomData<&'a Number>,
253}
254
255impl<'a> Negated<'a> {
256 /// `n` with the opposite sign, for as long as `n` is borrowed.
257 #[inline(always)]
258 pub(super) fn new(n: &'a Number) -> Self {
259 Negated {
260 number: ManuallyDrop::new(Number {
261 // SAFETY: the copy shares the vector of `n`, which stays borrowed, and so
262 // unchanged and not freed, while it lives. It is never written through: `Negated`
263 // gives out shared references only. It is never dropped: the vector is freed
264 // once, by `n`.
265 value: unsafe { ptr::read(&n.value) },
266 negative: !n.negative,
267 byte_order: n.byte_order,
268 }),
269 borrowed: PhantomData,
270 }
271 }
272}
273
274impl Deref for Negated<'_> {
275 type Target = Number;
276
277 #[inline(always)]
278 fn deref(&self) -> &Number {
279 &self.number
280 }
281}