1use crate::error::Result;
7use crate::limbs::{ct_compare, limb_sub_borrow};
8use crate::types::BigIntCore;
9
10#[cfg(feature = "alloc")]
11use crate::types::BigInt;
12
13#[cfg(feature = "alloc")]
17pub fn sub_magnitude(a: &BigInt, b: &BigInt, result: &mut BigInt) -> Result<bool> {
18 let n = a.limb_count().max(b.limb_count());
19 result.ensure_capacity(n)?;
20
21 let a_limbs = a.limbs();
22 let b_limbs = b.limbs();
23 let result_limbs = result.limbs_mut();
24
25 let mut borrow = 0u64;
26
27 for i in 0..n {
30 let a_val = if i < a_limbs.len() { a_limbs[i] } else { 0 };
31 let b_val = if i < b_limbs.len() { b_limbs[i] } else { 0 };
32
33 let (diff, borrow_out) = limb_sub_borrow(a_val, b_val, borrow);
34 if i < result_limbs.len() {
35 result_limbs[i] = diff;
36 }
37 borrow = borrow_out;
38 }
39
40 let is_negative = borrow != 0;
41
42 if is_negative {
44 for i in 0..n {
46 if i < result_limbs.len() {
47 result_limbs[i] = !result_limbs[i];
48 }
49 }
50
51 let mut carry = 1u64;
53 for i in 0..n {
54 if i < result_limbs.len() {
55 let (sum, carry_out) = crate::limbs::limb_add_carry(result_limbs[i], 0, carry);
56 result_limbs[i] = sum;
57 carry = carry_out;
58 }
59 }
60 }
61
62 result.canonicalize()?;
63 Ok(is_negative)
64}
65
66#[cfg(feature = "alloc")]
68pub fn sub(a: &BigInt, b: &BigInt) -> Result<BigInt> {
69 if b.is_zero() {
71 return Ok(a.clone());
72 }
73 if a.is_zero() {
74 let mut result = b.clone();
75 result.set_sign(!b.sign()); return Ok(result);
77 }
78
79 let cmp = ct_compare(a.limbs(), b.limbs());
81 let a_gt_b = (cmp & 1) != 0;
82 let a_eq_b = cmp == 0;
83
84 if a_eq_b {
85 let max_limbs = a.max_limbs().max(b.max_limbs());
87 return Ok(BigInt::new(max_limbs));
88 }
89
90 let max_limbs = a.max_limbs().max(b.max_limbs());
91 let mut result = BigInt::new(max_limbs);
92
93 let is_negative = if a_gt_b {
94 sub_magnitude(a, b, &mut result)?
96 } else {
97 sub_magnitude(b, a, &mut result)?
99 };
100
101 let final_sign = if a.sign() == b.sign() {
103 if a_gt_b { a.sign() } else { !a.sign() }
105 } else {
106 if a_gt_b { a.sign() } else { b.sign() }
109 };
110
111 result.set_sign(final_sign ^ is_negative);
112 Ok(result)
113}
114
115#[cfg(feature = "alloc")]
117pub fn sub_assign(a: &mut BigInt, b: &BigInt) -> Result<()> {
118 let result = sub(a, b)?;
119 *a = result;
120 Ok(())
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_sub_simple() {
129 let a = BigInt::from_u64(20, 10);
130 let b = BigInt::from_u64(10, 10);
131 let result = sub(&a, &b).unwrap();
132 assert_eq!(result.limbs()[0], 10);
133 assert!(!result.sign());
134 }
135
136 #[test]
137 fn test_sub_with_borrow() {
138 let a = BigInt::from_u64(10, 10);
139 let b = BigInt::from_u64(20, 10);
140 let result = sub(&a, &b).unwrap();
141 assert!(result.sign() || result.is_zero());
143 }
144}