1use crate::float::Float;
2use crate::int::{CastInto, Int};
3
4fn trunc<F: Float, R: Float>(a: F) -> R
5where
6 F::Int: CastInto<u64>,
7 F::Int: CastInto<u32>,
8 u64: CastInto<F::Int>,
9 u32: CastInto<F::Int>,
10
11 R::Int: CastInto<u32>,
12 u32: CastInto<R::Int>,
13 F::Int: CastInto<R::Int>,
14{
15 let src_zero = F::Int::ZERO;
16 let src_one = F::Int::ONE;
17 let src_bits = F::BITS;
18 let src_exp_bias = F::EXPONENT_BIAS;
19
20 let src_min_normal = F::IMPLICIT_BIT;
21 let src_significand_mask = F::SIGNIFICAND_MASK;
22 let src_infinity = F::EXPONENT_MASK;
23 let src_sign_mask = F::SIGN_MASK;
24 let src_abs_mask = src_sign_mask - src_one;
25 let round_mask = (src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)) - src_one;
26 let halfway = src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS - 1);
27 let src_qnan = src_one << (F::SIGNIFICAND_BITS - 1);
28 let src_nan_code = src_qnan - src_one;
29
30 let dst_zero = R::Int::ZERO;
31 let dst_one = R::Int::ONE;
32 let dst_bits = R::BITS;
33 let dst_inf_exp = R::EXPONENT_MAX;
34 let dst_exp_bias = R::EXPONENT_BIAS;
35
36 let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast();
37 let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast();
38 let underflow: F::Int = underflow_exponent << F::SIGNIFICAND_BITS;
39 let overflow: F::Int = overflow_exponent << F::SIGNIFICAND_BITS;
40
41 let dst_qnan = R::Int::ONE << (R::SIGNIFICAND_BITS - 1);
42 let dst_nan_code = dst_qnan - dst_one;
43
44 let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS;
45 // Break a into a sign and representation of the absolute value.
46 let a_abs = a.repr() & src_abs_mask;
47 let sign = a.repr() & src_sign_mask;
48 let mut abs_result: R::Int;
49
50 if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) {
51 // The exponent of a is within the range of normal numbers in the
52 // destination format. We can convert by simply right-shifting with
53 // rounding and adjusting the exponent.
54 abs_result = (a_abs >> sign_bits_delta).cast();
55 let tmp = src_exp_bias.wrapping_sub(dst_exp_bias) << R::SIGNIFICAND_BITS;
56 abs_result = abs_result.wrapping_sub(tmp.cast());
57
58 let round_bits = a_abs & round_mask;
59 if round_bits > halfway {
60 // Round to nearest.
61 abs_result += dst_one;
62 } else if round_bits == halfway {
63 // Tie to even.
64 abs_result += abs_result & dst_one;
65 };
66 } else if a_abs > src_infinity {
67 // a is NaN.
68 // Conjure the result by beginning with infinity, setting the qNaN
69 // bit and inserting the (truncated) trailing NaN field.
70 abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast();
71 abs_result |= dst_qnan;
72 abs_result |= dst_nan_code
73 & ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast();
74 } else if a_abs >= overflow {
75 // a overflows to infinity.
76 abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast();
77 } else {
78 // a underflows on conversion to the destination type or is an exact
79 // zero. The result may be a denormal or zero. Extract the exponent
80 // to get the shift amount for the denormalization.
81 let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast();
82 let shift = src_exp_bias - dst_exp_bias - a_exp + 1;
83
84 let significand = (a.repr() & src_significand_mask) | src_min_normal;
85
86 // Right shift by the denormalization amount with sticky.
87 if shift > F::SIGNIFICAND_BITS {
88 abs_result = dst_zero;
89 } else {
90 let sticky = if (significand << (src_bits - shift)) != src_zero {
91 src_one
92 } else {
93 src_zero
94 };
95 let denormalized_significand: F::Int = significand >> shift | sticky;
96 abs_result =
97 (denormalized_significand >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast();
98 let round_bits = denormalized_significand & round_mask;
99 // Round to nearest
100 if round_bits > halfway {
101 abs_result += dst_one;
102 }
103 // Ties to even
104 else if round_bits == halfway {
105 abs_result += abs_result & dst_one;
106 };
107 }
108 }
109
110 // Apply the signbit to the absolute value.
111 R::from_repr(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast())
112}
113
114intrinsics! {
115 #[avr_skip]
116 #[aapcs_on_arm]
117 #[arm_aeabi_alias = __aeabi_d2f]
118 pub extern "C" fn __truncdfsf2(a: f64) -> f32 {
119 trunc(a)
120 }
121
122 #[cfg(target_arch = "arm")]
123 pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 {
124 a as f32
125 }
126}
127