1use crate::float::Float;
2use crate::int::{CastInto, Int, MinInt};
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 R::Int: CastInto<u32>,
11 u32: CastInto<R::Int>,
12 F::Int: CastInto<R::Int>,
13{
14 let src_zero = F::Int::ZERO;
15 let src_one = F::Int::ONE;
16 let src_bits = F::BITS;
17 let src_exp_bias = F::EXP_BIAS;
18
19 let src_min_normal = F::IMPLICIT_BIT;
20 let src_sig_mask = F::SIG_MASK;
21 let src_infinity = F::EXP_MASK;
22 let src_sign_mask = F::SIGN_MASK;
23 let src_abs_mask = src_sign_mask - src_one;
24 let round_mask = (src_one << (F::SIG_BITS - R::SIG_BITS)) - src_one;
25 let halfway = src_one << (F::SIG_BITS - R::SIG_BITS - 1);
26 let src_qnan = src_one << (F::SIG_BITS - 1);
27 let src_nan_code = src_qnan - src_one;
28
29 let dst_zero = R::Int::ZERO;
30 let dst_one = R::Int::ONE;
31 let dst_bits = R::BITS;
32 let dst_inf_exp = R::EXP_SAT;
33 let dst_exp_bias = R::EXP_BIAS;
34
35 let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast();
36 let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast();
37 let underflow: F::Int = underflow_exponent << F::SIG_BITS;
38 let overflow: F::Int = overflow_exponent << F::SIG_BITS;
39
40 let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1);
41 let dst_nan_code = dst_qnan - dst_one;
42
43 let sig_bits_delta = F::SIG_BITS - R::SIG_BITS;
44 // Break a into a sign and representation of the absolute value.
45 let a_abs = a.to_bits() & src_abs_mask;
46 let sign = a.to_bits() & src_sign_mask;
47 let mut abs_result: R::Int;
48
49 if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) {
50 // The exponent of a is within the range of normal numbers in the
51 // destination format. We can convert by simply right-shifting with
52 // rounding and adjusting the exponent.
53 abs_result = (a_abs >> sig_bits_delta).cast();
54 // Cast before shifting to prevent overflow.
55 let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast();
56 let tmp = bias_diff << R::SIG_BITS;
57 abs_result = abs_result.wrapping_sub(tmp);
58
59 let round_bits = a_abs & round_mask;
60 if round_bits > halfway {
61 // Round to nearest.
62 abs_result += dst_one;
63 } else if round_bits == halfway {
64 // Tie to even.
65 abs_result += abs_result & dst_one;
66 };
67 } else if a_abs > src_infinity {
68 // a is NaN.
69 // Conjure the result by beginning with infinity, setting the qNaN
70 // bit and inserting the (truncated) trailing NaN field.
71 // Cast before shifting to prevent overflow.
72 let dst_inf_exp: R::Int = dst_inf_exp.cast();
73 abs_result = dst_inf_exp << R::SIG_BITS;
74 abs_result |= dst_qnan;
75 abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIG_BITS - R::SIG_BITS)).cast();
76 } else if a_abs >= overflow {
77 // a overflows to infinity.
78 // Cast before shifting to prevent overflow.
79 let dst_inf_exp: R::Int = dst_inf_exp.cast();
80 abs_result = dst_inf_exp << R::SIG_BITS;
81 } else {
82 // a underflows on conversion to the destination type or is an exact
83 // zero. The result may be a denormal or zero. Extract the exponent
84 // to get the shift amount for the denormalization.
85 let a_exp: u32 = (a_abs >> F::SIG_BITS).cast();
86 let shift = src_exp_bias - dst_exp_bias - a_exp + 1;
87
88 let significand = (a.to_bits() & src_sig_mask) | src_min_normal;
89
90 // Right shift by the denormalization amount with sticky.
91 if shift > F::SIG_BITS {
92 abs_result = dst_zero;
93 } else {
94 let sticky = if (significand << (src_bits - shift)) != src_zero {
95 src_one
96 } else {
97 src_zero
98 };
99 let denormalized_significand: F::Int = (significand >> shift) | sticky;
100 abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast();
101 let round_bits = denormalized_significand & round_mask;
102 // Round to nearest
103 if round_bits > halfway {
104 abs_result += dst_one;
105 }
106 // Ties to even
107 else if round_bits == halfway {
108 abs_result += abs_result & dst_one;
109 };
110 }
111 }
112
113 // Apply the signbit to the absolute value.
114 R::from_bits(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast())
115}
116
117intrinsics! {
118 #[avr_skip]
119 #[aapcs_on_arm]
120 #[arm_aeabi_alias = __aeabi_d2f]
121 pub extern "C" fn __truncdfsf2(a: f64) -> f32 {
122 trunc(a)
123 }
124}
125
126intrinsics! {
127 #[avr_skip]
128 #[aapcs_on_arm]
129 #[apple_f16_ret_abi]
130 #[arm_aeabi_alias = __aeabi_f2h]
131 #[cfg(f16_enabled)]
132 pub extern "C" fn __truncsfhf2(a: f32) -> f16 {
133 trunc(a)
134 }
135
136 #[avr_skip]
137 #[aapcs_on_arm]
138 #[apple_f16_ret_abi]
139 #[cfg(f16_enabled)]
140 pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 {
141 trunc(a)
142 }
143
144 #[avr_skip]
145 #[aapcs_on_arm]
146 #[apple_f16_ret_abi]
147 #[arm_aeabi_alias = __aeabi_d2h]
148 #[cfg(f16_enabled)]
149 pub extern "C" fn __truncdfhf2(a: f64) -> f16 {
150 trunc(a)
151 }
152
153 #[avr_skip]
154 #[aapcs_on_arm]
155 #[ppc_alias = __trunckfhf2]
156 #[cfg(all(f16_enabled, f128_enabled))]
157 pub extern "C" fn __trunctfhf2(a: f128) -> f16 {
158 trunc(a)
159 }
160
161 #[avr_skip]
162 #[aapcs_on_arm]
163 #[ppc_alias = __trunckfsf2]
164 #[cfg(f128_enabled)]
165 pub extern "C" fn __trunctfsf2(a: f128) -> f32 {
166 trunc(a)
167 }
168
169 #[avr_skip]
170 #[aapcs_on_arm]
171 #[ppc_alias = __trunckfdf2]
172 #[cfg(f128_enabled)]
173 pub extern "C" fn __trunctfdf2(a: f128) -> f64 {
174 trunc(a)
175 }
176}
177