| 1 | use crate::float::Float; |
| 2 | use crate::int::{CastInto, Int, MinInt}; |
| 3 | |
| 4 | fn trunc<F: Float, R: Float>(a: F) -> R |
| 5 | where |
| 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 | |
| 117 | intrinsics! { |
| 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 | |
| 126 | intrinsics! { |
| 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 | |