rust/fpnum/src/lib.rs
changeset 13928 5fdc41cd0841
parent 13927 cf28d7a2b7fe
child 13929 ff77c9920007
equal deleted inserted replaced
13927:cf28d7a2b7fe 13928:5fdc41cd0841
     7     value: u64,
     7     value: u64,
     8 }
     8 }
     9 
     9 
    10 impl FPNum {
    10 impl FPNum {
    11     #[inline]
    11     #[inline]
    12     fn new(numerator: i32, denominator: u32) -> Self {
    12     pub fn new(numerator: i32, denominator: u32) -> Self {
    13         FPNum::from(numerator) / denominator
    13         FPNum::from(numerator) / denominator
    14     }
    14     }
    15 
    15 
    16     #[inline]
    16     #[inline]
    17     fn signum(&self) -> i8 {
    17     pub fn signum(&self) -> i8 {
    18         if self.is_negative {
    18         if self.is_negative {
    19             -1
    19             -1
    20         } else {
    20         } else {
    21             1
    21             1
    22         }
    22         }
    23     }
    23     }
    24 
    24 
    25     #[inline]
    25     #[inline]
    26     fn is_negative(&self) -> bool {
    26     pub fn is_negative(&self) -> bool {
    27         self.is_negative
    27         self.is_negative
    28     }
    28     }
    29 
    29 
    30     #[inline]
    30     #[inline]
    31     fn is_positive(&self) -> bool {
    31     pub fn is_positive(&self) -> bool {
    32         !self.is_negative
    32         !self.is_negative
    33     }
    33     }
    34 
    34 
    35     #[inline]
    35     #[inline]
    36     fn is_zero(&self) -> bool {
    36     pub fn is_zero(&self) -> bool {
    37         self.value == 0
    37         self.value == 0
    38     }
    38     }
    39 
    39 
    40     #[inline]
    40     #[inline]
    41     fn abs(&self) -> Self {
    41     pub fn abs(&self) -> Self {
    42         Self {
    42         Self {
    43             is_negative: false,
    43             is_negative: false,
    44             value: self.value,
    44             value: self.value,
    45         }
    45         }
    46     }
    46     }
    47 
    47 
    48     #[inline]
    48     #[inline]
    49     fn round(&self) -> i64 {
    49     pub fn round(&self) -> i64 {
    50         if self.is_negative {
    50         if self.is_negative {
    51             -((self.value >> 32) as i64)
    51             -((self.value >> 32) as i64)
    52         } else {
    52         } else {
    53             (self.value >> 32) as i64
    53             (self.value >> 32) as i64
    54         }
    54         }
    55     }
    55     }
    56 
    56 
    57     #[inline]
    57     #[inline]
    58     fn sqr(&self) -> Self {
    58     pub fn sqr(&self) -> Self {
    59         Self {
    59         Self {
    60             is_negative: false,
    60             is_negative: false,
    61             value: ((self.value as u128).pow(2) >> 32) as u64,
    61             value: ((self.value as u128).pow(2) >> 32) as u64,
    62         }
    62         }
    63     }
    63     }
    64 
    64 
    65     fn sqrt(&self) -> Self {
    65     pub fn sqrt(&self) -> Self {
    66         debug_assert!(!self.is_negative);
    66         debug_assert!(!self.is_negative);
    67 
    67 
    68         let mut t: u64 = 0x4000000000000000;
    68         let mut t: u64 = 0x4000000000000000;
    69         let mut r: u64 = 0;
    69         let mut r: u64 = 0;
    70         let mut q = self.value;
    70         let mut q = self.value;
    85             value: r << 16,
    85             value: r << 16,
    86         }
    86         }
    87     }
    87     }
    88 
    88 
    89     #[inline]
    89     #[inline]
    90     fn with_sign(&self, is_negative: bool) -> FPNum {
    90     pub fn with_sign(&self, is_negative: bool) -> FPNum {
    91         FPNum{ is_negative, ..*self}
    91         FPNum{ is_negative, ..*self}
    92     }
    92     }
    93 
    93 
    94     #[inline]
    94     #[inline]
    95     fn with_sign_as(self, other: FPNum) -> FPNum {
    95     pub fn with_sign_as(self, other: FPNum) -> FPNum {
    96         self.with_sign(other.is_negative)
    96         self.with_sign(other.is_negative)
    97     }
    97     }
    98 
    98 
    99     #[inline]
    99     #[inline]
   100     fn point(self) -> FPPoint {
   100     pub fn point(self) -> FPPoint {
   101         FPPoint::new(self, self)
   101         FPPoint::new(self, self)
   102     }
   102     }
   103 }
   103 }
   104 
   104 
   105 impl From<i32> for FPNum {
   105 impl From<i32> for FPNum {
   284             value: self.value / rhs as u64,
   284             value: self.value / rhs as u64,
   285         }
   285         }
   286     }
   286     }
   287 }
   287 }
   288 
   288 
       
   289 #[macro_export]
   289 macro_rules! fp {
   290 macro_rules! fp {
   290     (-$n: tt / $d: tt) => { FPNum::new(-$n, $d) };
   291     (-$n: tt / $d: tt) => { FPNum::new(-$n, $d) };
   291     ($n: tt / $d: tt) => { FPNum::new($n, $d) };
   292     ($n: tt / $d: tt) => { FPNum::new($n, $d) };
   292     (-$n: tt) => { FPNum::from(-$n) };
   293     (-$n: tt) => { FPNum::from(-$n) };
   293     ($n: tt) => { FPNum::from($n) };
   294     ($n: tt) => { FPNum::from($n) };
   294 }
   295 }
   295 
   296 
   296 const LINEARIZE_TRESHOLD: u64 = 0x1_0000;
   297 const LINEARIZE_TRESHOLD: u64 = 0x1_0000;
   297 
   298 
   298 #[derive(Clone, Copy, Debug)]
   299 #[derive(Clone, Copy, Debug)]
   299 struct FPPoint {
   300 pub struct FPPoint {
   300     x_is_negative: bool,
   301     x_is_negative: bool,
   301     y_is_negative: bool,
   302     y_is_negative: bool,
   302     x_value: u64,
   303     x_value: u64,
   303     y_value: u64,
   304     y_value: u64,
   304 }
   305 }
   305 
   306 
   306 impl FPPoint {
   307 impl FPPoint {
   307     #[inline]
   308     #[inline]
   308     fn new(x: FPNum, y: FPNum) -> Self {
   309     pub fn new(x: FPNum, y: FPNum) -> Self {
   309         Self {
   310         Self {
   310             x_is_negative: x.is_negative,
   311             x_is_negative: x.is_negative,
   311             y_is_negative: y.is_negative,
   312             y_is_negative: y.is_negative,
   312             x_value: x.value,
   313             x_value: x.value,
   313             y_value: y.value
   314             y_value: y.value
   314         }
   315         }
   315     }
   316     }
   316 
   317 
   317     #[inline]
   318     #[inline]
   318     fn zero() -> FPPoint { FPPoint::new(fp!(0), fp!(0)) }
   319     pub fn zero() -> FPPoint { FPPoint::new(fp!(0), fp!(0)) }
   319 
   320 
   320     #[inline]
   321     #[inline]
   321     fn unit_x() -> FPPoint { FPPoint::new(fp!(1), fp!(0)) }
   322     pub fn unit_x() -> FPPoint { FPPoint::new(fp!(1), fp!(0)) }
   322 
   323 
   323     #[inline]
   324     #[inline]
   324     fn unit_y() -> FPPoint { FPPoint::new(fp!(0), fp!(1)) }
   325     pub fn unit_y() -> FPPoint { FPPoint::new(fp!(0), fp!(1)) }
   325 
   326 
   326     #[inline]
   327     #[inline]
   327     fn x(&self) -> FPNum {
   328     pub fn x(&self) -> FPNum {
   328         FPNum {
   329         FPNum {
   329             is_negative: self.x_is_negative,
   330             is_negative: self.x_is_negative,
   330             value: self.x_value
   331             value: self.x_value
   331         }
   332         }
   332     }
   333     }
   333 
   334 
   334     #[inline]
   335     #[inline]
   335     fn y(&self) -> FPNum {
   336     pub fn y(&self) -> FPNum {
   336         FPNum {
   337         FPNum {
   337             is_negative: self.y_is_negative,
   338             is_negative: self.y_is_negative,
   338             value: self.y_value
   339             value: self.y_value
   339         }
   340         }
   340     }
   341     }
   341 
   342 
   342     #[inline]
   343     #[inline]
   343     fn sqr_distance(&self) -> FPNum {
   344     pub fn max_norm(&self) -> FPNum {
       
   345         std::cmp::max(self.x(), self.y())
       
   346     }
       
   347 
       
   348     #[inline]
       
   349     pub fn sqr_distance(&self) -> FPNum {
   344         self.x().sqr() + self.y().sqr()
   350         self.x().sqr() + self.y().sqr()
   345     }
   351     }
   346 
   352 
   347     #[inline]
   353     #[inline]
   348     fn distance(&self) -> FPNum {
   354     pub fn distance(&self) -> FPNum {
   349         let r = self.x_value | self.y_value;
   355         let r = self.x_value | self.y_value;
   350         if r < LINEARIZE_TRESHOLD {
   356         if r < LINEARIZE_TRESHOLD {
   351             FPNum::from(r as u32)
   357             FPNum::from(r as u32)
   352         } else {
   358         } else {
   353             self.sqr_distance().sqrt()
   359             self.sqr_distance().sqrt()
   354         }
   360         }
   355     }
   361     }
   356 
   362 
   357     #[inline]
   363     #[inline]
   358     fn is_in_range(&self, radius: FPNum) -> bool {
   364     pub fn is_in_range(&self, radius: FPNum) -> bool {
   359         std::cmp::max(self.x(), self.y()) < radius
   365         self.max_norm() < radius && self.sqr_distance() < radius.sqr()
   360             && self.sqr_distance() < radius.sqr()
   366     }
   361     }
   367 
   362 
   368     #[inline]
   363     #[inline]
   369     pub fn dot(&self, other: &FPPoint) -> FPNum {
   364     fn dot(&self, other: &FPPoint) -> FPNum {
       
   365         self.x() * other.x() + self.y() * other.y()
   370         self.x() * other.x() + self.y() * other.y()
   366     }
   371     }
   367 }
   372 }
   368 
   373 
   369 impl PartialEq for FPPoint {
   374 impl PartialEq for FPPoint {
   419 scalar_bin_op_impl!(ops::Mul<FPNum>, mul);
   424 scalar_bin_op_impl!(ops::Mul<FPNum>, mul);
   420 scalar_bin_op_impl!(ops::Sub<FPNum>, sub);
   425 scalar_bin_op_impl!(ops::Sub<FPNum>, sub);
   421 scalar_bin_op_impl!(ops::Div<FPNum>, div);
   426 scalar_bin_op_impl!(ops::Div<FPNum>, div);
   422 
   427 
   423 #[inline]
   428 #[inline]
   424 fn distance<T>(x: T, y: T) -> FPNum
   429 pub fn distance<T>(x: T, y: T) -> FPNum
   425     where T: ops::Add + ops::Mul + Copy +
   430     where T: ops::Add + ops::Mul + Copy +
   426              From<<T as ops::Add>::Output> +
   431              From<<T as ops::Add>::Output> +
   427              From<<T as ops::Mul>::Output> +
   432              From<<T as ops::Mul>::Output> +
   428              Into<FPNum>
   433              Into<FPNum>
   429 {
   434 {