Skip to main content

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}