1use crate::env::{ExcFlags, FloatEnv, RoundMode};
6use crate::parts::{round_pack, unpack, FloatClass, FloatParts};
7use crate::types::{
8 BFloat16, BitOps, Float128, Float16, Float32, Float64, FloatFormat,
9 FloatX80,
10};
11
12const INT_BIT: u32 = 126;
13
14pub fn convert<F: FloatFormat, G: FloatFormat>(a: F, env: &mut FloatEnv) -> G {
20 let mut parts = unpack::<F>(a);
21 round_pack::<G>(&mut parts, env)
22}
23
24fn float_to_uint128<F: FloatFormat>(
31 a: F,
32 env: &mut FloatEnv,
33) -> (FloatParts, u128, bool) {
34 let parts = unpack::<F>(a);
35 if !matches!(parts.cls, FloatClass::Normal) {
36 return (parts, 0, false);
37 }
38
39 let shift = INT_BIT as i32 - parts.exp;
40 let rm = env.round_mode();
41
42 let (int_val, inexact) = if shift >= 128 {
43 (0u128, parts.frac != 0)
44 } else if shift > 0 {
45 let shift = shift as u32;
46 let remainder = parts.frac & ((1u128 << shift) - 1);
47 let truncated = parts.frac >> shift;
48 let inexact = remainder != 0;
49 let half = 1u128 << (shift - 1);
50 let up =
51 should_round_up_int(remainder, half, truncated, rm, parts.sign);
52 (if up { truncated + 1 } else { truncated }, inexact)
53 } else if shift == 0 {
54 (parts.frac, false)
55 } else {
56 let lshift = (-shift) as u32;
57 if lshift >= 128 {
58 return (parts, u128::MAX, false);
59 }
60 (parts.frac << lshift, false)
61 };
62
63 (parts, int_val, inexact)
64}
65
66pub fn to_i32<F: FloatFormat>(a: F, env: &mut FloatEnv) -> i32 {
71 let parts = unpack::<F>(a);
72
73 if parts.is_nan() {
74 env.raise(ExcFlags::INVALID);
75 return i32::MAX;
76 }
77 if parts.cls == FloatClass::Inf {
78 env.raise(ExcFlags::INVALID);
79 return if parts.sign { i32::MIN } else { i32::MAX };
80 }
81 if parts.cls == FloatClass::Zero {
82 return 0;
83 }
84
85 let (_, mag, inexact) = float_to_uint128::<F>(a, env);
86
87 if parts.sign {
88 if mag > 0x8000_0000 {
89 env.raise(ExcFlags::INVALID);
90 return i32::MIN;
91 }
92 if inexact {
93 env.raise(ExcFlags::INEXACT);
94 }
95 -(mag as i32)
96 } else {
97 if mag > 0x7FFF_FFFF {
98 env.raise(ExcFlags::INVALID);
99 return i32::MAX;
100 }
101 if inexact {
102 env.raise(ExcFlags::INEXACT);
103 }
104 mag as i32
105 }
106}
107
108pub fn to_u32<F: FloatFormat>(a: F, env: &mut FloatEnv) -> u32 {
109 let parts = unpack::<F>(a);
110
111 if parts.is_nan() {
112 env.raise(ExcFlags::INVALID);
113 return u32::MAX;
114 }
115 if parts.cls == FloatClass::Inf {
116 env.raise(ExcFlags::INVALID);
117 return if parts.sign { 0 } else { u32::MAX };
118 }
119 if parts.cls == FloatClass::Zero {
120 return 0;
121 }
122
123 if parts.sign {
124 let (_, mag, inexact) = float_to_uint128::<F>(a, env);
130 if mag > 0 {
131 env.raise(ExcFlags::INVALID);
132 } else if inexact {
133 env.raise(ExcFlags::INEXACT);
134 }
135 return 0;
136 }
137
138 let (_, mag, inexact) = float_to_uint128::<F>(a, env);
139 if mag > u32::MAX as u128 {
140 env.raise(ExcFlags::INVALID);
141 return u32::MAX;
142 }
143 if inexact {
144 env.raise(ExcFlags::INEXACT);
145 }
146 mag as u32
147}
148
149pub fn to_i64<F: FloatFormat>(a: F, env: &mut FloatEnv) -> i64 {
150 let parts = unpack::<F>(a);
151
152 if parts.is_nan() {
153 env.raise(ExcFlags::INVALID);
154 return i64::MAX;
155 }
156 if parts.cls == FloatClass::Inf {
157 env.raise(ExcFlags::INVALID);
158 return if parts.sign { i64::MIN } else { i64::MAX };
159 }
160 if parts.cls == FloatClass::Zero {
161 return 0;
162 }
163
164 let (_, mag, inexact) = float_to_uint128::<F>(a, env);
165
166 if parts.sign {
167 if mag > 0x8000_0000_0000_0000 {
168 env.raise(ExcFlags::INVALID);
169 return i64::MIN;
170 }
171 if inexact {
172 env.raise(ExcFlags::INEXACT);
173 }
174 -(mag as i64)
175 } else {
176 if mag > 0x7FFF_FFFF_FFFF_FFFF {
177 env.raise(ExcFlags::INVALID);
178 return i64::MAX;
179 }
180 if inexact {
181 env.raise(ExcFlags::INEXACT);
182 }
183 mag as i64
184 }
185}
186
187pub fn to_u64<F: FloatFormat>(a: F, env: &mut FloatEnv) -> u64 {
188 let parts = unpack::<F>(a);
189
190 if parts.is_nan() {
191 env.raise(ExcFlags::INVALID);
192 return u64::MAX;
193 }
194 if parts.cls == FloatClass::Inf {
195 env.raise(ExcFlags::INVALID);
196 return if parts.sign { 0 } else { u64::MAX };
197 }
198 if parts.cls == FloatClass::Zero {
199 return 0;
200 }
201
202 if parts.sign {
203 let (_, mag, inexact) = float_to_uint128::<F>(a, env);
204 if mag > 0 {
205 env.raise(ExcFlags::INVALID);
206 } else if inexact {
207 env.raise(ExcFlags::INEXACT);
208 }
209 return 0;
210 }
211
212 let (_, mag, inexact) = float_to_uint128::<F>(a, env);
213 if mag > u64::MAX as u128 {
214 env.raise(ExcFlags::INVALID);
215 return u64::MAX;
216 }
217 if inexact {
218 env.raise(ExcFlags::INEXACT);
219 }
220 mag as u64
221}
222
223fn should_round_up_int(
224 remainder: u128,
225 half: u128,
226 truncated: u128,
227 rm: RoundMode,
228 sign: bool,
229) -> bool {
230 match rm {
231 RoundMode::NearEven => {
232 if remainder > half {
233 true
234 } else if remainder == half {
235 truncated & 1 != 0
236 } else {
237 false
238 }
239 }
240 RoundMode::NearMaxMag => remainder >= half,
241 RoundMode::ToZero => false,
242 RoundMode::Down => sign && remainder != 0,
243 RoundMode::Up => !sign && remainder != 0,
244 RoundMode::Odd => {
245 if remainder != 0 {
246 truncated & 1 == 0
247 } else {
248 false
249 }
250 }
251 }
252}
253
254pub fn from_i32<F: FloatFormat>(a: i32, env: &mut FloatEnv) -> F {
259 if a == 0 {
260 return F::from_bits(<F::Bits as BitOps>::from_u128(0));
261 }
262 let sign = a < 0;
263 let mag = if sign {
264 (a as i64).unsigned_abs()
265 } else {
266 a as u64
267 };
268 from_uint_impl::<F>(mag as u128, sign, env)
269}
270
271pub fn from_u32<F: FloatFormat>(a: u32, env: &mut FloatEnv) -> F {
272 if a == 0 {
273 return F::from_bits(<F::Bits as BitOps>::from_u128(0));
274 }
275 from_uint_impl::<F>(a as u128, false, env)
276}
277
278pub fn from_i64<F: FloatFormat>(a: i64, env: &mut FloatEnv) -> F {
279 if a == 0 {
280 return F::from_bits(<F::Bits as BitOps>::from_u128(0));
281 }
282 let sign = a < 0;
283 let mag = a.unsigned_abs();
284 from_uint_impl::<F>(mag as u128, sign, env)
285}
286
287pub fn from_u64<F: FloatFormat>(a: u64, env: &mut FloatEnv) -> F {
288 if a == 0 {
289 return F::from_bits(<F::Bits as BitOps>::from_u128(0));
290 }
291 from_uint_impl::<F>(a as u128, false, env)
292}
293
294fn from_uint_impl<F: FloatFormat>(
295 mag: u128,
296 sign: bool,
297 env: &mut FloatEnv,
298) -> F {
299 if mag == 0 {
300 return F::from_bits(<F::Bits as BitOps>::from_u128(0));
301 }
302
303 let msb = 127 - mag.leading_zeros();
304 let exp = msb as i32;
305
306 let frac = if msb <= INT_BIT {
307 mag << (INT_BIT - msb)
308 } else {
309 let shift = msb - INT_BIT;
310 let sticky = if mag & ((1u128 << shift) - 1) != 0 {
311 1u128
312 } else {
313 0
314 };
315 (mag >> shift) | sticky
316 };
317
318 let mut parts = FloatParts {
319 sign,
320 exp,
321 frac,
322 cls: FloatClass::Normal,
323 };
324 round_pack::<F>(&mut parts, env)
325}
326
327macro_rules! impl_convert_from {
332 ($dst:ty, $src:ty, $method:ident) => {
333 impl $dst {
334 pub fn $method(v: $src, env: &mut FloatEnv) -> Self {
335 convert::<$src, $dst>(v, env)
336 }
337 }
338 };
339}
340
341impl_convert_from!(Float32, Float16, from_f16);
342impl_convert_from!(Float32, BFloat16, from_bf16);
343impl_convert_from!(Float32, Float64, from_f64);
344impl_convert_from!(Float32, Float128, from_f128);
345impl_convert_from!(Float32, FloatX80, from_fx80);
346
347impl_convert_from!(Float64, Float16, from_f16);
348impl_convert_from!(Float64, BFloat16, from_bf16);
349impl_convert_from!(Float64, Float32, from_f32);
350impl_convert_from!(Float64, Float128, from_f128);
351impl_convert_from!(Float64, FloatX80, from_fx80);
352
353impl_convert_from!(Float16, Float32, from_f32);
354impl_convert_from!(Float16, Float64, from_f64);
355impl_convert_from!(Float16, BFloat16, from_bf16);
356impl_convert_from!(Float16, Float128, from_f128);
357impl_convert_from!(Float16, FloatX80, from_fx80);
358
359impl_convert_from!(BFloat16, Float16, from_f16);
360impl_convert_from!(BFloat16, Float32, from_f32);
361impl_convert_from!(BFloat16, Float64, from_f64);
362impl_convert_from!(BFloat16, Float128, from_f128);
363impl_convert_from!(BFloat16, FloatX80, from_fx80);
364
365impl_convert_from!(Float128, Float16, from_f16);
366impl_convert_from!(Float128, BFloat16, from_bf16);
367impl_convert_from!(Float128, Float32, from_f32);
368impl_convert_from!(Float128, Float64, from_f64);
369impl_convert_from!(Float128, FloatX80, from_fx80);
370
371impl_convert_from!(FloatX80, Float16, from_f16);
372impl_convert_from!(FloatX80, BFloat16, from_bf16);
373impl_convert_from!(FloatX80, Float32, from_f32);
374impl_convert_from!(FloatX80, Float64, from_f64);
375impl_convert_from!(FloatX80, Float128, from_f128);
376
377macro_rules! impl_to_int {
378 ($ty:ty) => {
379 impl $ty {
380 pub fn to_i32(self, env: &mut FloatEnv) -> i32 {
381 to_i32::<Self>(self, env)
382 }
383 pub fn to_u32(self, env: &mut FloatEnv) -> u32 {
384 to_u32::<Self>(self, env)
385 }
386 pub fn to_i64(self, env: &mut FloatEnv) -> i64 {
387 to_i64::<Self>(self, env)
388 }
389 pub fn to_u64(self, env: &mut FloatEnv) -> u64 {
390 to_u64::<Self>(self, env)
391 }
392 }
393 };
394}
395
396impl_to_int!(Float16);
397impl_to_int!(BFloat16);
398impl_to_int!(Float32);
399impl_to_int!(Float64);
400impl_to_int!(Float128);
401impl_to_int!(FloatX80);
402
403macro_rules! impl_from_int {
404 ($ty:ty) => {
405 impl $ty {
406 pub fn from_i32(v: i32, env: &mut FloatEnv) -> Self {
407 from_i32::<Self>(v, env)
408 }
409 pub fn from_u32(v: u32, env: &mut FloatEnv) -> Self {
410 from_u32::<Self>(v, env)
411 }
412 pub fn from_i64(v: i64, env: &mut FloatEnv) -> Self {
413 from_i64::<Self>(v, env)
414 }
415 pub fn from_u64(v: u64, env: &mut FloatEnv) -> Self {
416 from_u64::<Self>(v, env)
417 }
418 }
419 };
420}
421
422impl_from_int!(Float16);
423impl_from_int!(BFloat16);
424impl_from_int!(Float32);
425impl_from_int!(Float64);
426impl_from_int!(Float128);
427impl_from_int!(FloatX80);