|
| 1 | +use float::Float; |
| 2 | +use int::{CastInto, Int}; |
| 3 | + |
| 4 | +/// Generic conversion from a wider to a narrower IEEE-754 floating-point type |
| 5 | +fn truncate<F: Float, R: Float>(a: F) -> R |
| 6 | +where |
| 7 | + F::Int: CastInto<u64>, |
| 8 | + u64: CastInto<F::Int>, |
| 9 | + F::Int: CastInto<u32>, |
| 10 | + u32: CastInto<F::Int>, |
| 11 | + u32: CastInto<R::Int>, |
| 12 | + R::Int: CastInto<u32>, |
| 13 | + F::Int: CastInto<R::Int>, |
| 14 | +{ |
| 15 | + let src_one = F::Int::ONE; |
| 16 | + let src_bits = F::BITS; |
| 17 | + let src_sign_bits = F::SIGNIFICAND_BITS; |
| 18 | + let src_exp_bias = F::EXPONENT_BIAS; |
| 19 | + let src_min_normal = F::IMPLICIT_BIT; |
| 20 | + let src_infinity = F::EXPONENT_MASK; |
| 21 | + let src_sign_mask = F::SIGN_MASK as F::Int; |
| 22 | + let src_abs_mask = src_sign_mask - src_one; |
| 23 | + let src_qnan = F::SIGNIFICAND_MASK; |
| 24 | + let src_nan_code = src_qnan - src_one; |
| 25 | + |
| 26 | + let dst_bits = R::BITS; |
| 27 | + let dst_sign_bits = R::SIGNIFICAND_BITS; |
| 28 | + let dst_inf_exp = R::EXPONENT_MAX; |
| 29 | + let dst_exp_bias = R::EXPONENT_BIAS; |
| 30 | + |
| 31 | + let dst_zero = R::Int::ZERO; |
| 32 | + let dst_one = R::Int::ONE; |
| 33 | + let dst_qnan = R::SIGNIFICAND_MASK; |
| 34 | + let dst_nan_code = dst_qnan - dst_one; |
| 35 | + |
| 36 | + let round_mask = (src_one << src_sign_bits - dst_sign_bits) - src_one; |
| 37 | + let half = src_one << src_sign_bits - dst_sign_bits - 1; |
| 38 | + let underflow_exp = src_exp_bias + 1 - dst_exp_bias; |
| 39 | + let overflow_exp = src_exp_bias + dst_inf_exp - dst_exp_bias; |
| 40 | + let underflow: F::Int = underflow_exp.cast(); // << src_sign_bits; |
| 41 | + let overflow: F::Int = overflow_exp.cast(); //<< src_sign_bits; |
| 42 | + |
| 43 | + let a_abs = a.repr() & src_abs_mask; |
| 44 | + let sign = a.repr() & src_sign_mask; |
| 45 | + let mut abs_result: R::Int; |
| 46 | + |
| 47 | + let src_underflow = underflow << src_sign_bits; |
| 48 | + let src_overflow = overflow << src_sign_bits; |
| 49 | + |
| 50 | + if a_abs.wrapping_sub(src_underflow) < a_abs.wrapping_sub(src_overflow) { |
| 51 | + // The exponent of a is within the range of normal numbers |
| 52 | + let bias_delta: R::Int = (src_exp_bias - dst_exp_bias).cast(); |
| 53 | + abs_result = a_abs.cast(); |
| 54 | + abs_result = abs_result >> src_sign_bits - dst_sign_bits; |
| 55 | + abs_result = abs_result - bias_delta.wrapping_shl(dst_sign_bits); |
| 56 | + let round_bits: F::Int = a_abs & round_mask; |
| 57 | + abs_result += if round_bits > half { |
| 58 | + dst_one |
| 59 | + } else { |
| 60 | + abs_result & dst_one |
| 61 | + }; |
| 62 | + } else if a_abs > src_infinity { |
| 63 | + // a is NaN. |
| 64 | + // Conjure the result by beginning with infinity, setting the qNaN |
| 65 | + // bit and inserting the (truncated) trailing NaN field |
| 66 | + let nan_result: R::Int = (a_abs & src_nan_code).cast(); |
| 67 | + abs_result = dst_inf_exp.cast(); |
| 68 | + abs_result = abs_result.wrapping_shl(dst_sign_bits); |
| 69 | + abs_result |= dst_qnan; |
| 70 | + abs_result |= (nan_result >> (src_sign_bits - dst_sign_bits)) & dst_nan_code; |
| 71 | + } else if a_abs >= src_overflow { |
| 72 | + // a overflows to infinity. |
| 73 | + abs_result = dst_inf_exp.cast(); |
| 74 | + abs_result = abs_result.wrapping_shl(dst_sign_bits); |
| 75 | + } else { |
| 76 | + // a underflows on conversion to the destination type or is an exact |
| 77 | + // zero. The result may be a denormal or zero. Extract the exponent |
| 78 | + // to get the shift amount for the denormalization. |
| 79 | + let a_exp = a_abs >> src_sign_bits; |
| 80 | + let mut shift: u32 = a_exp.cast(); |
| 81 | + shift = src_exp_bias - dst_exp_bias - shift + 1; |
| 82 | + |
| 83 | + let significand = (a.repr() & src_sign_mask) | src_min_normal; |
| 84 | + if shift > src_sign_bits { |
| 85 | + abs_result = dst_zero; |
| 86 | + } else { |
| 87 | + let sticky = significand << src_bits - shift; |
| 88 | + let mut denormalized_significand: R::Int = significand.cast(); |
| 89 | + let sticky_shift: u32 = sticky.cast(); |
| 90 | + denormalized_significand = denormalized_significand >> (shift | sticky_shift); |
| 91 | + abs_result = denormalized_significand >> src_sign_bits - dst_sign_bits; |
| 92 | + let round_bits = denormalized_significand & round_mask.cast(); |
| 93 | + if round_bits > half.cast() { |
| 94 | + abs_result += dst_one; // Round to nearest |
| 95 | + } else if round_bits == half.cast() { |
| 96 | + abs_result += abs_result & dst_one; // Ties to even |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + // Finally apply the sign bit |
| 101 | + let s = sign >> src_bits - dst_bits; |
| 102 | + R::from_repr(abs_result | s.cast()) |
| 103 | +} |
| 104 | + |
| 105 | +intrinsics! { |
| 106 | + #[aapcs_on_arm] |
| 107 | + #[arm_aeabi_alias = __aeabi_d2f] |
| 108 | + pub extern "C" fn __truncdfsf2(a: f64) -> f32 { |
| 109 | + truncate(a) |
| 110 | + } |
| 111 | + |
| 112 | + #[cfg(target_arch = "arm")] |
| 113 | + pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { |
| 114 | + a as f32 |
| 115 | + } |
| 116 | +} |
0 commit comments