rust/fpnum/src/lib.rs
changeset 13925 2ee07e751171
parent 13905 fed924791e06
child 13926 2717a5289d88
equal deleted inserted replaced
13924:a140f28decc4 13925:2ee07e751171
    81 
    81 
    82         Self {
    82         Self {
    83             is_negative: false,
    83             is_negative: false,
    84             value: r << 16,
    84             value: r << 16,
    85         }
    85         }
       
    86     }
       
    87 
       
    88     fn with_sign(&self, is_negative: bool) -> FPNum {
       
    89         FPNum{ is_negative, ..*self}
       
    90     }
       
    91 
       
    92     #[inline]
       
    93     fn with_sign_as(self, other: FPNum) -> FPNum {
       
    94         self.with_sign(other.is_negative)
    86     }
    95     }
    87 }
    96 }
    88 
    97 
    89 impl From<i32> for FPNum {
    98 impl From<i32> for FPNum {
    90     #[inline]
    99     #[inline]
   275     ($n: tt / $d: tt) => { FPNum::new($n, $d) };
   284     ($n: tt / $d: tt) => { FPNum::new($n, $d) };
   276     (-$n: tt) => { FPNum::from(-$n) };
   285     (-$n: tt) => { FPNum::from(-$n) };
   277     ($n: tt) => { FPNum::from($n) };
   286     ($n: tt) => { FPNum::from($n) };
   278 }
   287 }
   279 
   288 
       
   289 const LINEARIZE_TRESHOLD: u64 = 0x1_0000;
       
   290 
       
   291 #[derive(Clone, Copy, Debug)]
       
   292 struct FPPoint {
       
   293     x_is_negative: bool,
       
   294     y_is_negative: bool,
       
   295     x_value: u64,
       
   296     y_value: u64,
       
   297 }
       
   298 
       
   299 impl FPPoint {
       
   300     #[inline]
       
   301     fn new(x: FPNum, y: FPNum) -> Self {
       
   302         Self {
       
   303             x_is_negative: x.is_negative,
       
   304             y_is_negative: y.is_negative,
       
   305             x_value: x.value,
       
   306             y_value: y.value
       
   307         }
       
   308     }
       
   309 
       
   310     #[inline]
       
   311     fn zero() -> FPPoint { FPPoint::new(fp!(0), fp!(0)) }
       
   312 
       
   313     #[inline]
       
   314     fn unit_x() -> FPPoint { FPPoint::new(fp!(1), fp!(0)) }
       
   315 
       
   316     #[inline]
       
   317     fn unit_y() -> FPPoint { FPPoint::new(fp!(0), fp!(1)) }
       
   318 
       
   319     #[inline]
       
   320     fn x(&self) -> FPNum {
       
   321         FPNum {
       
   322             is_negative: self.x_is_negative,
       
   323             value: self.x_value
       
   324         }
       
   325     }
       
   326 
       
   327     #[inline]
       
   328     fn y(&self) -> FPNum {
       
   329         FPNum {
       
   330             is_negative: self.y_is_negative,
       
   331             value: self.y_value
       
   332         }
       
   333     }
       
   334 
       
   335     #[inline]
       
   336     fn sqr_distance(&self) -> FPNum {
       
   337         self.x().sqr() + self.y().sqr()
       
   338     }
       
   339 
       
   340     #[inline]
       
   341     fn distance(&self) -> FPNum {
       
   342         let r = self.x_value | self.y_value;
       
   343         if r < LINEARIZE_TRESHOLD {
       
   344             FPNum::from(r as u32)
       
   345         } else {
       
   346             self.sqr_distance().sqrt()
       
   347         }
       
   348     }
       
   349 
       
   350     #[inline]
       
   351     fn is_in_range(&self, radius: FPNum) -> bool {
       
   352         std::cmp::max(self.x(), self.y()) < radius
       
   353             && self.sqr_distance() < radius.sqr()
       
   354     }
       
   355 
       
   356     #[inline]
       
   357     fn dot(&self, other: &FPPoint) -> FPNum {
       
   358         self.x() * other.x() + self.y() * other.y()
       
   359     }
       
   360 }
       
   361 
       
   362 impl PartialEq for FPPoint {
       
   363     #[inline]
       
   364     fn eq(&self, other: &Self) -> bool {
       
   365         self.x() == other.x() && self.y() == other.y()
       
   366     }
       
   367 }
       
   368 
       
   369 impl Eq for FPPoint {}
       
   370 
       
   371 impl ops::Neg for FPPoint {
       
   372     type Output = Self;
       
   373 
       
   374     #[inline]
       
   375     fn neg(self) -> Self {
       
   376         Self::new(-self.x(), -self.y())
       
   377     }
       
   378 }
       
   379 
       
   380 macro_rules! bin_op_impl {
       
   381     ($op: path, $name: tt) => {
       
   382         impl $op for FPPoint {
       
   383             type Output = Self;
       
   384 
       
   385             #[inline]
       
   386             fn $name(self, rhs: Self) -> Self {
       
   387                 Self::new(self.x().$name(rhs.x()),
       
   388                           self.y().$name(rhs.y()))
       
   389             }
       
   390         }
       
   391     }
       
   392 }
       
   393 
       
   394 bin_op_impl!(ops::Add, add);
       
   395 bin_op_impl!(ops::Sub, sub);
       
   396 bin_op_impl!(ops::Mul, mul);
       
   397 
       
   398 #[inline]
       
   399 fn distance<T>(x: T, y: T) -> FPNum
       
   400     where T: ops::Add + ops::Mul + Copy +
       
   401              From<<T as ops::Add>::Output> +
       
   402              From<<T as ops::Mul>::Output> +
       
   403              Into<FPNum>
       
   404 {
       
   405     let sqr: FPNum = T::from(T::from(x * x) + T::from(y * y)).into();
       
   406     sqr.sqrt()
       
   407 }
       
   408 
   280 /* TODO:
   409 /* TODO:
   281  Distance
       
   282  DistanceI
       
   283  SignAs
       
   284  AngleSin
   410  AngleSin
   285  AngleCos
   411  AngleCos
   286 */
   412 */
   287 
   413 
   288 #[cfg(test)]
   414 #[cfg(test)]
   311     assert!(z.is_zero());
   437     assert!(z.is_zero());
   312     assert!(z.is_positive());
   438     assert!(z.is_positive());
   313     assert!((-z).is_negative);
   439     assert!((-z).is_negative);
   314     assert_eq!(n - n, z);
   440     assert_eq!(n - n, z);
   315     assert_eq!(-n + n, z);
   441     assert_eq!(-n + n, z);
       
   442     assert_eq!(z.with_sign_as(-n), -z);
   316 }
   443 }
   317 
   444 
   318 #[test]
   445 #[test]
   319 fn ord() {
   446 fn ord() {
   320     let z = fp!(0);
   447     let z = fp!(0);
   350 
   477 
   351     assert_eq!(n2_25.sqrt(), n1_5);
   478     assert_eq!(n2_25.sqrt(), n1_5);
   352 
   479 
   353     assert_eq!((n1_5 * n1_5 * n1_5.sqr()).sqrt(), n2_25);
   480     assert_eq!((n1_5 * n1_5 * n1_5.sqr()).sqrt(), n2_25);
   354 }
   481 }
       
   482 
       
   483 #[test]
       
   484 fn point() {
       
   485     let z = FPPoint::zero();
       
   486     let p = FPPoint::new(fp!(1), fp!(-2));
       
   487 
       
   488     assert_eq!(p.sqr_distance(), fp!(5));
       
   489     assert_eq!(p + -p, FPPoint::zero());
       
   490     assert_eq!(p * z, z);
       
   491     assert_eq!(p.dot(&z), fp!(0));
       
   492     assert_eq!(distance(4, 3), fp!(5));
       
   493 }