1use crate::env::{FloatEnv, RoundMode};
5use crate::parts::{nan_propagate, round_pack, unpack, FloatClass, FloatParts};
6use crate::types::{
7 BFloat16, Float128, Float16, Float32, Float64, FloatFormat, FloatX80,
8};
9
10pub fn add<F: FloatFormat>(a: F, b: F, env: &mut FloatEnv) -> F {
12 let pa = unpack::<F>(a);
13 let pb = unpack::<F>(b);
14 add_parts::<F>(&pa, &pb, env)
15}
16
17pub fn sub<F: FloatFormat>(a: F, b: F, env: &mut FloatEnv) -> F {
19 let pa = unpack::<F>(a);
20 let mut pb = unpack::<F>(b);
21 pb.sign = !pb.sign;
22 add_parts::<F>(&pa, &pb, env)
23}
24
25fn add_parts<F: FloatFormat>(
26 a: &FloatParts,
27 b: &FloatParts,
28 env: &mut FloatEnv,
29) -> F {
30 if a.is_nan() || b.is_nan() {
32 let r = nan_propagate(a, b, env);
33 let mut r = r;
34 return round_pack::<F>(&mut r, env);
35 }
36
37 if a.cls == FloatClass::Inf {
39 if b.cls == FloatClass::Inf {
40 if a.sign != b.sign {
41 return crate::parts::return_nan::<F>(env);
43 }
44 let mut r = *a;
46 return round_pack::<F>(&mut r, env);
47 }
48 let mut r = *a;
49 return round_pack::<F>(&mut r, env);
50 }
51 if b.cls == FloatClass::Inf {
52 let mut r = *b;
53 return round_pack::<F>(&mut r, env);
54 }
55
56 if a.cls == FloatClass::Zero {
58 if b.cls == FloatClass::Zero {
59 let sign = if a.sign == b.sign {
61 a.sign
62 } else {
63 env.round_mode() == RoundMode::Down
64 };
65 let mut r = FloatParts {
66 sign,
67 exp: 0,
68 frac: 0,
69 cls: FloatClass::Zero,
70 };
71 return round_pack::<F>(&mut r, env);
72 }
73 let mut r = *b;
74 return round_pack::<F>(&mut r, env);
75 }
76 if b.cls == FloatClass::Zero {
77 let mut r = *a;
78 return round_pack::<F>(&mut r, env);
79 }
80
81 if a.sign == b.sign {
83 add_normal::<F>(a, b, env)
84 } else {
85 sub_normal::<F>(a, b, env)
86 }
87}
88
89fn add_normal<F: FloatFormat>(
91 a: &FloatParts,
92 b: &FloatParts,
93 env: &mut FloatEnv,
94) -> F {
95 let (mut big, mut small) = if a.exp >= b.exp { (*a, *b) } else { (*b, *a) };
96
97 let exp_diff = (big.exp - small.exp) as u32;
98
99 if exp_diff > 0 {
101 if exp_diff >= 128 {
102 small.frac = if small.frac != 0 { 1 } else { 0 };
104 } else {
105 let sticky = if small.frac & ((1u128 << exp_diff) - 1) != 0 {
106 1u128
107 } else {
108 0
109 };
110 small.frac = (small.frac >> exp_diff) | sticky;
111 }
112 }
113
114 big.frac = big.frac.wrapping_add(small.frac);
115 let mut result = FloatParts {
118 sign: big.sign,
119 exp: big.exp,
120 frac: big.frac,
121 cls: FloatClass::Normal,
122 };
123 round_pack::<F>(&mut result, env)
124}
125
126fn sub_normal<F: FloatFormat>(
129 a: &FloatParts,
130 b: &FloatParts,
131 env: &mut FloatEnv,
132) -> F {
133 let (big, small, result_sign) = if a.exp > b.exp {
135 (*a, *b, a.sign)
136 } else if a.exp < b.exp {
137 (*b, *a, b.sign)
138 } else if a.frac > b.frac {
139 (*a, *b, a.sign)
140 } else if a.frac < b.frac {
141 (*b, *a, b.sign)
142 } else {
143 let sign = env.round_mode() == RoundMode::Down;
146 let mut r = FloatParts {
147 sign,
148 exp: 0,
149 frac: 0,
150 cls: FloatClass::Zero,
151 };
152 return round_pack::<F>(&mut r, env);
153 };
154
155 let exp_diff = (big.exp - small.exp) as u32;
156
157 let mut small_frac = small.frac;
158 if exp_diff > 0 {
159 if exp_diff >= 128 {
160 small_frac = if small_frac != 0 { 1 } else { 0 };
161 } else {
162 let sticky = if small_frac & ((1u128 << exp_diff) - 1) != 0 {
163 1u128
164 } else {
165 0
166 };
167 small_frac = (small_frac >> exp_diff) | sticky;
168 }
169 }
170
171 let frac = big.frac.wrapping_sub(small_frac);
172
173 if frac == 0 {
174 let sign = env.round_mode() == RoundMode::Down;
175 let mut r = FloatParts {
176 sign,
177 exp: 0,
178 frac: 0,
179 cls: FloatClass::Zero,
180 };
181 return round_pack::<F>(&mut r, env);
182 }
183
184 let mut result = FloatParts {
185 sign: result_sign,
186 exp: big.exp,
187 frac,
188 cls: FloatClass::Normal,
189 };
190 round_pack::<F>(&mut result, env)
191}
192
193macro_rules! impl_add_sub {
198 ($ty:ty) => {
199 impl $ty {
200 pub fn add(self, other: Self, env: &mut FloatEnv) -> Self {
201 add::<Self>(self, other, env)
202 }
203 pub fn sub(self, other: Self, env: &mut FloatEnv) -> Self {
204 sub::<Self>(self, other, env)
205 }
206 }
207 };
208}
209
210impl_add_sub!(Float16);
211impl_add_sub!(BFloat16);
212impl_add_sub!(Float32);
213impl_add_sub!(Float64);
214impl_add_sub!(Float128);
215impl_add_sub!(FloatX80);