291 } |
295 } |
292 } |
296 } |
293 |
297 |
294 #[macro_export] |
298 #[macro_export] |
295 macro_rules! fp { |
299 macro_rules! fp { |
296 (-$n: tt / $d: tt) => { FPNum::new(-$n, $d) }; |
300 (-$n: tt / $d: tt) => { |
297 ($n: tt / $d: tt) => { FPNum::new($n, $d) }; |
301 FPNum::new(-$n, $d) |
298 (-$n: tt) => { FPNum::from(-$n) }; |
302 }; |
299 ($n: tt) => { FPNum::from($n) }; |
303 ($n: tt / $d: tt) => { |
|
304 FPNum::new($n, $d) |
|
305 }; |
|
306 (-$n: tt) => { |
|
307 FPNum::from(-$n) |
|
308 }; |
|
309 ($n: tt) => { |
|
310 FPNum::from($n) |
|
311 }; |
300 } |
312 } |
301 |
313 |
302 const LINEARIZE_TRESHOLD: u64 = 0x1_0000; |
314 const LINEARIZE_TRESHOLD: u64 = 0x1_0000; |
303 |
315 |
304 #[derive(Clone, Copy, Debug)] |
316 #[derive(Clone, Copy, Debug)] |
314 pub fn new(x: FPNum, y: FPNum) -> Self { |
326 pub fn new(x: FPNum, y: FPNum) -> Self { |
315 Self { |
327 Self { |
316 x_is_negative: x.is_negative, |
328 x_is_negative: x.is_negative, |
317 y_is_negative: y.is_negative, |
329 y_is_negative: y.is_negative, |
318 x_value: x.value, |
330 x_value: x.value, |
319 y_value: y.value |
331 y_value: y.value, |
320 } |
332 } |
321 } |
333 } |
322 |
334 |
323 #[inline] |
335 #[inline] |
324 pub fn zero() -> FPPoint { FPPoint::new(fp!(0), fp!(0)) } |
336 pub fn zero() -> FPPoint { |
325 |
337 FPPoint::new(fp!(0), fp!(0)) |
326 #[inline] |
338 } |
327 pub fn unit_x() -> FPPoint { FPPoint::new(fp!(1), fp!(0)) } |
339 |
328 |
340 #[inline] |
329 #[inline] |
341 pub fn unit_x() -> FPPoint { |
330 pub fn unit_y() -> FPPoint { FPPoint::new(fp!(0), fp!(1)) } |
342 FPPoint::new(fp!(1), fp!(0)) |
|
343 } |
|
344 |
|
345 #[inline] |
|
346 pub fn unit_y() -> FPPoint { |
|
347 FPPoint::new(fp!(0), fp!(1)) |
|
348 } |
331 |
349 |
332 #[inline] |
350 #[inline] |
333 pub fn x(&self) -> FPNum { |
351 pub fn x(&self) -> FPNum { |
334 FPNum { |
352 FPNum { |
335 is_negative: self.x_is_negative, |
353 is_negative: self.x_is_negative, |
336 value: self.x_value |
354 value: self.x_value, |
337 } |
355 } |
338 } |
356 } |
339 |
357 |
340 #[inline] |
358 #[inline] |
341 pub fn y(&self) -> FPNum { |
359 pub fn y(&self) -> FPNum { |
342 FPNum { |
360 FPNum { |
343 is_negative: self.y_is_negative, |
361 is_negative: self.y_is_negative, |
344 value: self.y_value |
362 value: self.y_value, |
345 } |
363 } |
346 } |
364 } |
347 |
365 |
348 #[inline] |
366 #[inline] |
349 pub fn max_norm(&self) -> FPNum { |
367 pub fn max_norm(&self) -> FPNum { |
359 pub fn distance(&self) -> FPNum { |
377 pub fn distance(&self) -> FPNum { |
360 let r = self.x_value | self.y_value; |
378 let r = self.x_value | self.y_value; |
361 if r < LINEARIZE_TRESHOLD { |
379 if r < LINEARIZE_TRESHOLD { |
362 FPNum::from(r as u32) |
380 FPNum::from(r as u32) |
363 } else { |
381 } else { |
364 self.sqr_distance().sqrt() |
382 let mut sqr: u128 = (self.x_value as u128).pow(2) + (self.y_value as u128).pow(2); |
|
383 |
|
384 let mut t: u128 = 0x40000000_00000000_00000000_00000000; |
|
385 let mut r: u128 = 0; |
|
386 |
|
387 for _ in 0..64 { |
|
388 let s = r + t; |
|
389 r >>= 1; |
|
390 |
|
391 if s <= sqr { |
|
392 sqr -= s; |
|
393 r += t; |
|
394 } |
|
395 t >>= 2; |
|
396 } |
|
397 |
|
398 FPNum { |
|
399 is_negative: false, |
|
400 value: r as u64, |
|
401 } |
365 } |
402 } |
366 } |
403 } |
367 |
404 |
368 #[inline] |
405 #[inline] |
369 pub fn is_in_range(&self, radius: FPNum) -> bool { |
406 pub fn is_in_range(&self, radius: FPNum) -> bool { |
399 impl $op for FPPoint { |
436 impl $op for FPPoint { |
400 type Output = Self; |
437 type Output = Self; |
401 |
438 |
402 #[inline] |
439 #[inline] |
403 fn $name(self, rhs: Self) -> Self { |
440 fn $name(self, rhs: Self) -> Self { |
404 Self::new(self.x().$name(rhs.x()), |
441 Self::new(self.x().$name(rhs.x()), self.y().$name(rhs.y())) |
405 self.y().$name(rhs.y())) |
442 } |
406 } |
443 } |
407 } |
444 }; |
408 } |
|
409 } |
445 } |
410 |
446 |
411 macro_rules! right_scalar_bin_op_impl { |
447 macro_rules! right_scalar_bin_op_impl { |
412 ($($op: tt)::+, $name: tt) => { |
448 ($($op: tt)::+, $name: tt) => { |
413 impl $($op)::+<FPNum> for FPPoint { |
449 impl $($op)::+<FPNum> for FPPoint { |
475 bin_assign_op_impl!(FPPoint, ops::AddAssign<FPNum>, add_assign, +); |
511 bin_assign_op_impl!(FPPoint, ops::AddAssign<FPNum>, add_assign, +); |
476 bin_assign_op_impl!(FPPoint, ops::SubAssign<FPNum>, sub_assign, -); |
512 bin_assign_op_impl!(FPPoint, ops::SubAssign<FPNum>, sub_assign, -); |
477 bin_assign_op_impl!(FPPoint, ops::MulAssign<FPNum>, mul_assign, *); |
513 bin_assign_op_impl!(FPPoint, ops::MulAssign<FPNum>, mul_assign, *); |
478 bin_assign_op_impl!(FPPoint, ops::DivAssign<FPNum>, div_assign, /); |
514 bin_assign_op_impl!(FPPoint, ops::DivAssign<FPNum>, div_assign, /); |
479 |
515 |
480 #[inline] |
|
481 pub fn distance<T>(x: T, y: T) -> FPNum |
516 pub fn distance<T>(x: T, y: T) -> FPNum |
482 where T: ops::Add + ops::Mul + Copy + |
517 where |
483 From<<T as ops::Add>::Output> + |
518 T: Into<i64> + std::fmt::Debug, |
484 From<<T as ops::Mul>::Output> + |
|
485 Into<FPNum> |
|
486 { |
519 { |
487 let sqr: FPNum = T::from(T::from(x * x) + T::from(y * y)).into(); |
520 let mut sqr: u128 = (x.into().pow(2) as u128).shl(64) + (y.into().pow(2) as u128).shl(64); |
488 sqr.sqrt() |
521 |
|
522 let mut t: u128 = 0x40000000_00000000_00000000_00000000; |
|
523 let mut r: u128 = 0; |
|
524 |
|
525 for _ in 0..64 { |
|
526 let s = r + t; |
|
527 r >>= 1; |
|
528 |
|
529 if s <= sqr { |
|
530 sqr -= s; |
|
531 r += t; |
|
532 } |
|
533 t >>= 2; |
|
534 } |
|
535 |
|
536 FPNum { |
|
537 is_negative: false, |
|
538 value: r as u64, |
|
539 } |
489 } |
540 } |
490 |
541 |
491 /* TODO: |
542 /* TODO: |
492 AngleSin |
543 AngleSin |
493 AngleCos |
544 AngleCos |
494 */ |
545 */ |
495 |
546 |
496 #[cfg(test)] |
547 #[cfg(test)] |
497 #[test] |
548 #[test] |
498 fn basics() { |
549 fn basics() { |
499 let n = fp!(15/2); |
550 let n = fp!(15 / 2); |
500 assert!(n.is_positive()); |
551 assert!(n.is_positive()); |
501 assert!(!n.is_negative()); |
552 assert!(!n.is_negative()); |
502 |
553 |
503 assert!(!(-n).is_positive()); |
554 assert!(!(-n).is_positive()); |
504 assert!((-n).is_negative()); |
555 assert!((-n).is_negative()); |
505 |
556 |
506 assert_eq!(-(-n), n); |
557 assert_eq!(-(-n), n); |
507 assert_eq!((-n).abs(), n); |
558 assert_eq!((-n).abs(), n); |
508 assert_eq!(-n, fp!(-15/2)); |
559 assert_eq!(-n, fp!(-15 / 2)); |
509 |
560 |
510 assert_eq!(n.round(), 7); |
561 assert_eq!(n.round(), 7); |
511 assert_eq!((-n).round(), -7); |
562 assert_eq!((-n).round(), -7); |
512 } |
563 } |
513 |
564 |
514 #[test] |
565 #[test] |
515 fn zero() { |
566 fn zero() { |
516 let z = fp!(0); |
567 let z = fp!(0); |
517 let n = fp!(15/2); |
568 let n = fp!(15 / 2); |
518 |
569 |
519 assert!(z.is_zero()); |
570 assert!(z.is_zero()); |
520 assert!(z.is_positive()); |
571 assert!(z.is_positive()); |
521 assert!((-z).is_negative); |
572 assert!((-z).is_negative); |
522 assert_eq!(n - n, z); |
573 assert_eq!(n - n, z); |
525 } |
576 } |
526 |
577 |
527 #[test] |
578 #[test] |
528 fn ord() { |
579 fn ord() { |
529 let z = fp!(0); |
580 let z = fp!(0); |
530 let n1_5 = fp!(3/2); |
581 let n1_5 = fp!(3 / 2); |
531 let n2_25 = fp!(9/4); |
582 let n2_25 = fp!(9 / 4); |
532 |
583 |
533 assert!(!(z > z)); |
584 assert!(!(z > z)); |
534 assert!(!(z < z)); |
585 assert!(!(z < z)); |
535 assert!(n2_25 > n1_5); |
586 assert!(n2_25 > n1_5); |
536 assert!(-n2_25 < n1_5); |
587 assert!(-n2_25 < n1_5); |
537 assert!(-n2_25 < -n1_5); |
588 assert!(-n2_25 < -n1_5); |
538 } |
589 } |
539 |
590 |
540 #[test] |
591 #[test] |
541 fn arith() { |
592 fn arith() { |
542 let n1_5 = fp!(3/2); |
593 let n1_5 = fp!(3 / 2); |
543 let n2_25 = fp!(9/4); |
594 let n2_25 = fp!(9 / 4); |
544 let n_0_15 = fp!(-15/100); |
595 let n_0_15 = fp!(-15 / 100); |
545 |
596 |
546 assert_eq!(n1_5 + n1_5, fp!(3)); |
597 assert_eq!(n1_5 + n1_5, fp!(3)); |
547 assert_eq!(-n1_5 - n1_5, fp!(-3)); |
598 assert_eq!(-n1_5 - n1_5, fp!(-3)); |
548 |
599 |
549 assert_eq!(n1_5 * n1_5, n2_25); |
600 assert_eq!(n1_5 * n1_5, n2_25); |
561 |
612 |
562 assert_eq!((n1_5 * n1_5 * n1_5.sqr()).sqrt(), n2_25); |
613 assert_eq!((n1_5 * n1_5 * n1_5.sqr()).sqrt(), n2_25); |
563 |
614 |
564 let mut m = fp!(1); |
615 let mut m = fp!(1); |
565 m += n1_5; |
616 m += n1_5; |
566 assert_eq!(m, fp!(5/2)); |
617 assert_eq!(m, fp!(5 / 2)); |
|
618 } |
|
619 |
|
620 #[test] |
|
621 fn test_distance_high_values() { |
|
622 assert_eq!(distance(1_000_000i32, 0), fp!(1_000_000)); |
|
623 assert_eq!( |
|
624 FPPoint::new(fp!(1_000_000), fp!(0)).distance(), |
|
625 fp!(1_000_000) |
|
626 ); |
567 } |
627 } |
568 |
628 |
569 #[test] |
629 #[test] |
570 fn point() { |
630 fn point() { |
571 let z = FPPoint::zero(); |
631 let z = FPPoint::zero(); |
572 let n = fp!(16/9); |
632 let n = fp!(16 / 9); |
573 let p = FPPoint::new(fp!(1), fp!(-2)); |
633 let p = FPPoint::new(fp!(1), fp!(-2)); |
574 |
634 |
575 assert_eq!(p.sqr_distance(), fp!(5)); |
635 assert_eq!(p.sqr_distance(), fp!(5)); |
576 assert_eq!(p + -p, FPPoint::zero()); |
636 assert_eq!(p + -p, FPPoint::zero()); |
577 assert_eq!(p * z, z); |
637 assert_eq!(p * z, z); |