oxinum_float/native/
float_add.rs1use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
10
11use oxinum_core::Sign;
12use oxinum_int::native::BigUint;
13
14use super::float::{BigFloat, RoundingMode};
15use super::nonfinite::{nonfinite_propagate, BinOp};
16
17impl BigFloat {
18 pub fn add_ref(&self, other: &BigFloat) -> BigFloat {
21 self.add_ref_with_mode(other, RoundingMode::HalfEven)
22 }
23
24 pub fn add_ref_with_mode(&self, other: &BigFloat, mode: RoundingMode) -> BigFloat {
27 if let Some(result) = nonfinite_propagate(self, other, BinOp::Add) {
29 return result;
30 }
31 let target_prec = self.precision.max(other.precision);
32 if self.is_zero() {
33 return other.clone().round_to_precision(target_prec, mode);
34 }
35 if other.is_zero() {
36 return self.clone().round_to_precision(target_prec, mode);
37 }
38
39 let (common_exp, lhs_mag, rhs_mag) = align_to_common_exp(self, other);
42
43 let (out_sign, out_mag) = match (self.sign, other.sign) {
45 (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
46 (self.sign, &lhs_mag + &rhs_mag)
47 }
48 _ => {
49 if lhs_mag >= rhs_mag {
53 let diff = lhs_mag.checked_sub(&rhs_mag).unwrap_or_else(BigUint::zero);
55 (self.sign, diff)
56 } else {
57 let diff = rhs_mag.checked_sub(&lhs_mag).unwrap_or_else(BigUint::zero);
58 (other.sign, diff)
59 }
60 }
61 };
62
63 BigFloat::from_parts(out_sign, out_mag, common_exp, target_prec, mode)
65 }
66
67 pub fn sub_ref(&self, other: &BigFloat) -> BigFloat {
70 self.sub_ref_with_mode(other, RoundingMode::HalfEven)
71 }
72
73 pub fn sub_ref_with_mode(&self, other: &BigFloat, mode: RoundingMode) -> BigFloat {
76 self.add_ref_with_mode(&other.neg(), mode)
77 }
78}
79
80fn align_to_common_exp(a: &BigFloat, b: &BigFloat) -> (i64, BigUint, BigUint) {
84 if a.exponent == b.exponent {
85 (a.exponent, a.mantissa.clone(), b.mantissa.clone())
86 } else if a.exponent > b.exponent {
87 let shift = (a.exponent - b.exponent) as u64;
88 let lhs = a.mantissa.shl_bits(shift);
89 (b.exponent, lhs, b.mantissa.clone())
90 } else {
91 let shift = (b.exponent - a.exponent) as u64;
92 let rhs = b.mantissa.shl_bits(shift);
93 (a.exponent, a.mantissa.clone(), rhs)
94 }
95}
96
97impl Add<&BigFloat> for &BigFloat {
102 type Output = BigFloat;
103 #[inline]
104 fn add(self, rhs: &BigFloat) -> BigFloat {
105 self.add_ref(rhs)
106 }
107}
108
109impl Add<BigFloat> for BigFloat {
110 type Output = BigFloat;
111 #[inline]
112 fn add(self, rhs: BigFloat) -> BigFloat {
113 self.add_ref(&rhs)
114 }
115}
116
117impl Add<&BigFloat> for BigFloat {
118 type Output = BigFloat;
119 #[inline]
120 fn add(self, rhs: &BigFloat) -> BigFloat {
121 self.add_ref(rhs)
122 }
123}
124
125impl Add<BigFloat> for &BigFloat {
126 type Output = BigFloat;
127 #[inline]
128 fn add(self, rhs: BigFloat) -> BigFloat {
129 self.add_ref(&rhs)
130 }
131}
132
133impl Sub<&BigFloat> for &BigFloat {
134 type Output = BigFloat;
135 #[inline]
136 fn sub(self, rhs: &BigFloat) -> BigFloat {
137 self.sub_ref(rhs)
138 }
139}
140
141impl Sub<BigFloat> for BigFloat {
142 type Output = BigFloat;
143 #[inline]
144 fn sub(self, rhs: BigFloat) -> BigFloat {
145 self.sub_ref(&rhs)
146 }
147}
148
149impl Sub<&BigFloat> for BigFloat {
150 type Output = BigFloat;
151 #[inline]
152 fn sub(self, rhs: &BigFloat) -> BigFloat {
153 self.sub_ref(rhs)
154 }
155}
156
157impl Sub<BigFloat> for &BigFloat {
158 type Output = BigFloat;
159 #[inline]
160 fn sub(self, rhs: BigFloat) -> BigFloat {
161 self.sub_ref(&rhs)
162 }
163}
164
165impl AddAssign<&BigFloat> for BigFloat {
166 #[inline]
167 fn add_assign(&mut self, rhs: &BigFloat) {
168 *self = self.add_ref(rhs);
169 }
170}
171
172impl AddAssign<BigFloat> for BigFloat {
173 #[inline]
174 fn add_assign(&mut self, rhs: BigFloat) {
175 *self = self.add_ref(&rhs);
176 }
177}
178
179impl SubAssign<&BigFloat> for BigFloat {
180 #[inline]
181 fn sub_assign(&mut self, rhs: &BigFloat) {
182 *self = self.sub_ref(rhs);
183 }
184}
185
186impl SubAssign<BigFloat> for BigFloat {
187 #[inline]
188 fn sub_assign(&mut self, rhs: BigFloat) {
189 *self = self.sub_ref(&rhs);
190 }
191}
192
193impl Neg for BigFloat {
194 type Output = BigFloat;
195 #[inline]
196 fn neg(self) -> BigFloat {
197 BigFloat::neg(&self)
198 }
199}
200
201impl Neg for &BigFloat {
202 type Output = BigFloat;
203 #[inline]
204 fn neg(self) -> BigFloat {
205 BigFloat::neg(self)
206 }
207}