fp.rs 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. const FP_SHIFT: i32 = 16;
  2. const FP_MULT: f64 = 65536.0;
  3. const FP_HALF: f64 = 32768.0;
  4. const FP_FLOOR_MASK: i32 = !((1 << FP_SHIFT) - 1);
  5. pub trait ToFixedPoint {
  6. fn to_fp(&self) -> i32;
  7. }
  8. pub trait FromFixedPoint {
  9. fn to_f64(&self) -> f64;
  10. fn to_i32(&self) -> i32;
  11. }
  12. impl ToFixedPoint for f64 {
  13. fn to_fp(&self) -> i32 {
  14. (*self * FP_MULT) as i32
  15. }
  16. }
  17. impl ToFixedPoint for i32 {
  18. fn to_fp(&self) -> i32 {
  19. *self << FP_SHIFT
  20. }
  21. }
  22. impl FromFixedPoint for i32 {
  23. fn to_f64(&self) -> f64 {
  24. *self as f64 / FP_MULT
  25. }
  26. fn to_i32(&self) -> i32 {
  27. *self >> FP_SHIFT
  28. }
  29. }
  30. pub const fn add(a: i32, b: i32) -> i32 {
  31. a + b
  32. }
  33. pub const fn sub(a: i32, b: i32) -> i32 {
  34. a - b
  35. }
  36. pub const fn mul(a: i32, b: i32) -> i32 {
  37. ((a as i64 * b as i64) >> FP_SHIFT) as i32
  38. }
  39. pub const fn div(a: i32, b: i32) -> i32 {
  40. (((a as i64) << FP_SHIFT) / b as i64) as i32
  41. }
  42. pub const fn floor(a: i32) -> i32 {
  43. a & FP_FLOOR_MASK
  44. }
  45. #[cfg(test)]
  46. mod test {
  47. use super::*;
  48. #[test]
  49. fn f64_add() {
  50. let test_pairs = [
  51. (0.5, 0.5),
  52. (-0.754, 0.123)
  53. ];
  54. for (a, b) in test_pairs {
  55. let fp_sum = add(a.to_fp(), b.to_fp());
  56. float_cmp::assert_approx_eq!(f64, fp_sum.to_f64(), a + b, epsilon = 0.003, ulps = 2)
  57. }
  58. }
  59. #[test]
  60. fn f64_sub() {
  61. let test_pairs = [
  62. (0.5, 0.5),
  63. (-0.754, 0.123)
  64. ];
  65. for (a, b) in test_pairs {
  66. let fp_diff = sub(a.to_fp(), b.to_fp());
  67. float_cmp::assert_approx_eq!(f64, fp_diff.to_f64(), a - b, epsilon = 0.003, ulps = 2)
  68. }
  69. }
  70. #[test]
  71. fn f64_mul() {
  72. let test_pairs = [
  73. (0.5, 0.5),
  74. (-0.754, 0.123)
  75. ];
  76. for (a, b) in test_pairs {
  77. let fp_prod = mul(a.to_fp(), b.to_fp());
  78. float_cmp::assert_approx_eq!(f64, fp_prod.to_f64(), a * b, epsilon = 0.003, ulps = 2)
  79. }
  80. }
  81. #[test]
  82. fn f64_div() {
  83. let test_pairs = [
  84. (0.5, 0.5),
  85. (-0.754, 0.123)
  86. ];
  87. for (a, b) in test_pairs {
  88. let fp_quot = div(a.to_fp(), b.to_fp());
  89. float_cmp::assert_approx_eq!(f64, fp_quot.to_f64(), a / b, epsilon = 0.003, ulps = 2)
  90. }
  91. }
  92. }