conv.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. use float::Float;
  2. use int::Int;
  3. macro_rules! fp_overflow {
  4. (infinity, $fty:ty, $sign: expr) => {
  5. return {
  6. <$fty as Float>::from_parts(
  7. $sign,
  8. <$fty as Float>::exponent_max() as <$fty as Float>::Int,
  9. 0 as <$fty as Float>::Int)
  10. }
  11. }
  12. }
  13. macro_rules! int_to_float {
  14. ($intrinsic:ident: $ity:ty, $fty:ty) => {
  15. int_to_float!($intrinsic: $ity, $fty, "C");
  16. };
  17. ($intrinsic:ident: $ity:ty, $fty:ty, $abi:tt) => {
  18. pub extern $abi fn $intrinsic(i: $ity) -> $fty {
  19. if i == 0 {
  20. return 0.0
  21. }
  22. let mant_dig = <$fty>::significand_bits() + 1;
  23. let exponent_bias = <$fty>::exponent_bias();
  24. let n = <$ity>::bits();
  25. let (s, a) = i.extract_sign();
  26. let mut a = a;
  27. // number of significant digits
  28. let sd = n - a.leading_zeros();
  29. // exponent
  30. let mut e = sd - 1;
  31. if <$ity>::bits() < mant_dig {
  32. return <$fty>::from_parts(s,
  33. (e + exponent_bias) as <$fty as Float>::Int,
  34. (a as <$fty as Float>::Int) << (mant_dig - e - 1))
  35. }
  36. a = if sd > mant_dig {
  37. /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
  38. * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
  39. * 12345678901234567890123456
  40. * 1 = msb 1 bit
  41. * P = bit MANT_DIG-1 bits to the right of 1
  42. * Q = bit MANT_DIG bits to the right of 1
  43. * R = "or" of all bits to the right of Q
  44. */
  45. let mant_dig_plus_one = mant_dig + 1;
  46. let mant_dig_plus_two = mant_dig + 2;
  47. a = if sd == mant_dig_plus_one {
  48. a << 1
  49. } else if sd == mant_dig_plus_two {
  50. a
  51. } else {
  52. (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt |
  53. ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt
  54. };
  55. /* finish: */
  56. a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */
  57. a += 1; /* round - this step may add a significant bit */
  58. a >>= 2; /* dump Q and R */
  59. /* a is now rounded to mant_dig or mant_dig+1 bits */
  60. if (a & (1 << mant_dig)) != 0 {
  61. a >>= 1; e += 1;
  62. }
  63. a
  64. /* a is now rounded to mant_dig bits */
  65. } else {
  66. a.wrapping_shl(mant_dig - sd)
  67. /* a is now rounded to mant_dig bits */
  68. };
  69. <$fty>::from_parts(s,
  70. (e + exponent_bias) as <$fty as Float>::Int,
  71. a as <$fty as Float>::Int)
  72. }
  73. }
  74. }
  75. macro_rules! int_to_float_unadj_on_win {
  76. ($intrinsic:ident: $ity:ty, $fty:ty) => {
  77. #[cfg(all(windows, target_pointer_width="64"))]
  78. int_to_float!($intrinsic: $ity, $fty, "unadjusted");
  79. #[cfg(not(all(windows, target_pointer_width="64")))]
  80. int_to_float!($intrinsic: $ity, $fty, "C");
  81. };
  82. }
  83. int_to_float!(__floatsisf: i32, f32);
  84. int_to_float!(__floatsidf: i32, f64);
  85. int_to_float!(__floatdidf: i64, f64);
  86. int_to_float_unadj_on_win!(__floattisf: i128, f32);
  87. int_to_float_unadj_on_win!(__floattidf: i128, f64);
  88. int_to_float!(__floatunsisf: u32, f32);
  89. int_to_float!(__floatunsidf: u32, f64);
  90. int_to_float!(__floatundidf: u64, f64);
  91. int_to_float_unadj_on_win!(__floatuntisf: u128, f32);
  92. int_to_float_unadj_on_win!(__floatuntidf: u128, f64);
  93. #[derive(PartialEq, Debug)]
  94. enum Sign {
  95. Positive,
  96. Negative
  97. }
  98. macro_rules! float_to_int {
  99. ($intrinsic:ident: $fty:ty, $ity:ty) => {
  100. float_to_int!($intrinsic: $fty, $ity, "C");
  101. };
  102. ($intrinsic:ident: $fty:ty, $ity:ty, $abi:tt) => {
  103. pub extern $abi fn $intrinsic(f: $fty) -> $ity {
  104. let fixint_min = <$ity>::min_value();
  105. let fixint_max = <$ity>::max_value();
  106. let fixint_bits = <$ity>::bits() as usize;
  107. let fixint_unsigned = fixint_min == 0;
  108. let sign_bit = <$fty>::sign_mask();
  109. let significand_bits = <$fty>::significand_bits() as usize;
  110. let exponent_bias = <$fty>::exponent_bias() as usize;
  111. //let exponent_max = <$fty>::exponent_max() as usize;
  112. // Break a into sign, exponent, significand
  113. let a_rep = <$fty>::repr(f);
  114. let a_abs = a_rep & !sign_bit;
  115. // this is used to work around -1 not being available for unsigned
  116. let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative };
  117. let mut exponent = (a_abs >> significand_bits) as usize;
  118. let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit();
  119. // if < 1 or unsigned & negative
  120. if exponent < exponent_bias ||
  121. fixint_unsigned && sign == Sign::Negative {
  122. return 0
  123. }
  124. exponent -= exponent_bias;
  125. // If the value is infinity, saturate.
  126. // If the value is too large for the integer type, 0.
  127. if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
  128. return if sign == Sign::Positive {fixint_max} else {fixint_min}
  129. }
  130. // If 0 <= exponent < significand_bits, right shift to get the result.
  131. // Otherwise, shift left.
  132. // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
  133. let r = if exponent < significand_bits {
  134. (significand >> (significand_bits - exponent)) as $ity
  135. } else {
  136. (significand as $ity) << (exponent - significand_bits)
  137. };
  138. if sign == Sign::Negative {
  139. (!r).wrapping_add(1)
  140. } else {
  141. r
  142. }
  143. }
  144. }
  145. }
  146. macro_rules! float_to_int_unadj_on_win {
  147. ($intrinsic:ident: $fty:ty, $ity:ty) => {
  148. #[cfg(all(windows, target_pointer_width="64"))]
  149. float_to_int!($intrinsic: $fty, $ity, "unadjusted");
  150. #[cfg(not(all(windows, target_pointer_width="64")))]
  151. float_to_int!($intrinsic: $fty, $ity, "C");
  152. };
  153. }
  154. float_to_int!(__fixsfsi: f32, i32);
  155. float_to_int!(__fixsfdi: f32, i64);
  156. float_to_int_unadj_on_win!(__fixsfti: f32, i128);
  157. float_to_int!(__fixdfsi: f64, i32);
  158. float_to_int!(__fixdfdi: f64, i64);
  159. float_to_int_unadj_on_win!(__fixdfti: f64, i128);
  160. float_to_int!(__fixunssfsi: f32, u32);
  161. float_to_int!(__fixunssfdi: f32, u64);
  162. float_to_int_unadj_on_win!(__fixunssfti: f32, u128);
  163. float_to_int!(__fixunsdfsi: f64, u32);
  164. float_to_int!(__fixunsdfdi: f64, u64);
  165. float_to_int_unadj_on_win!(__fixunsdfti: f64, u128);