# HG changeset patch # User unC0Rr # Date 1734614335 -3600 # Node ID 6633961698add338e1943bb0abe9c6c9d78bf070 # Parent a5eaeefa4ab3c0c1141903a86b55fecb137cc70b Make wider range of numbers representable with FPNum on the cost of smaller precision diff -r a5eaeefa4ab3 -r 6633961698ad rust/fpnum/src/lib.rs --- a/rust/fpnum/src/lib.rs Thu Dec 19 12:43:38 2024 +0100 +++ b/rust/fpnum/src/lib.rs Thu Dec 19 14:18:55 2024 +0100 @@ -1,4 +1,5 @@ use std::{cmp, ops}; +use std::marker::PhantomData; use saturate::SaturatingInto; const POSITIVE_MASK: u64 = 0x0000_0000_0000_0000; @@ -13,16 +14,20 @@ } } +struct FracBits; #[derive(Clone, Debug, Copy)] -pub struct FPNum { +pub struct FixedPoint { sign_mask: u64, value: u64, + _marker: PhantomData>, } -impl FPNum { +pub type FPNum = FixedPoint<20>; + +impl FixedPoint { #[inline] pub fn new(numerator: i32, denominator: u32) -> Self { - FPNum::from(numerator) / denominator + Self::from(numerator) / denominator } #[inline] @@ -50,24 +55,26 @@ Self { sign_mask: POSITIVE_MASK, value: self.value, + _marker: self._marker, } } #[inline] - pub fn round(&self) -> i32 { - ((self.value >> 32) as i32 ^ self.sign_mask as i32).wrapping_sub(self.sign_mask as i32) + pub fn round(&self) -> i64 { + ((self.value >> FRAC_BITS) as i64 ^ self.sign_mask as i64).wrapping_sub(self.sign_mask as i64) } #[inline] - pub const fn abs_round(&self) -> u32 { - (self.value >> 32) as u32 + pub const fn abs_round(&self) -> u64 { + self.value >> FRAC_BITS } #[inline] pub fn sqr(&self) -> Self { Self { sign_mask: 0, - value: ((self.value as u128).pow(2) >> 32).saturating_into(), + value: ((self.value as u128).pow(2) >> FRAC_BITS).saturating_into(), + _marker: self._marker } } @@ -77,92 +84,95 @@ Self { sign_mask: POSITIVE_MASK, - value: integral_sqrt(self.value) << 16, + value: integral_sqrt(self.value) << (FRAC_BITS / 2), + _marker: self._marker } } #[inline] - pub fn with_sign(&self, is_negative: bool) -> FPNum { - FPNum { + pub fn with_sign(&self, is_negative: bool) -> Self { + Self { sign_mask: bool_mask(is_negative), ..*self } } #[inline] - pub const fn with_sign_as(self, other: FPNum) -> FPNum { - FPNum { + pub const fn with_sign_as(self, other: Self) -> Self { + Self { sign_mask: other.sign_mask, ..self } } - +/* #[inline] pub const fn point(self) -> FPPoint { FPPoint::new(self, self) } - +*/ #[inline] const fn temp_i128(self) -> i128 { ((self.value ^ self.sign_mask) as i128).wrapping_sub(self.sign_mask as i128) } } -impl From for FPNum { +impl From for FixedPoint { #[inline] fn from(n: i32) -> Self { - FPNum { + Self { sign_mask: bool_mask(n < 0), - value: (n.abs() as u64) << 32, + value: (n.abs() as u64) << FRAC_BITS, + _marker: PhantomData, } } } -impl From for FPNum { +impl From for FixedPoint { #[inline] fn from(n: u32) -> Self { Self { sign_mask: POSITIVE_MASK, - value: (n as u64) << 32, + value: (n as u64) << FRAC_BITS, + _marker: PhantomData, } } } -impl From for f64 { +impl From> for f64 { #[inline] - fn from(n: FPNum) -> Self { + fn from(n: FixedPoint) -> Self { if n.is_negative() { - n.value as f64 / -0x1_0000_0000i64 as f64 + n.value as f64 / -(1i64 << FRAC_BITS) as f64 } else { - n.value as f64 / 0x1_0000_0000i64 as f64 + n.value as f64 / (1i64 << FRAC_BITS) as f64 } } } -impl PartialEq for FPNum { +impl PartialEq for FixedPoint { #[inline] fn eq(&self, other: &Self) -> bool { self.value == other.value && (self.sign_mask == other.sign_mask || self.value == 0) } } -impl Eq for FPNum {} +impl Eq for FixedPoint {} -impl PartialOrd for FPNum { +impl PartialOrd for FixedPoint { #[inline] fn partial_cmp(&self, rhs: &Self) -> Option { Some(self.cmp(rhs)) } } -impl Ord for FPNum { +impl Ord for FixedPoint { #[inline] fn cmp(&self, rhs: &Self) -> cmp::Ordering { self.temp_i128().cmp(&(rhs.temp_i128())) } } -impl ops::Add for FPNum { +impl ops::Add for FixedPoint { type Output = Self; #[inline] @@ -172,11 +182,12 @@ Self { sign_mask: mask, value: ((tmp as u64) ^ mask).wrapping_sub(mask), + _marker: PhantomData, } } } -impl ops::Sub for FPNum { +impl ops::Sub for FixedPoint { type Output = Self; #[inline] @@ -186,7 +197,7 @@ } } -impl ops::Neg for FPNum { +impl ops::Neg for FixedPoint { type Output = Self; #[inline] @@ -194,23 +205,25 @@ Self { sign_mask: !self.sign_mask, value: self.value, + _marker: PhantomData, } } } -impl ops::Mul for FPNum { +impl ops::Mul for FixedPoint { type Output = Self; #[inline] fn mul(self, rhs: Self) -> Self { Self { sign_mask: self.sign_mask ^ rhs.sign_mask, - value: ((self.value as u128 * rhs.value as u128) >> 32).saturating_into(), + value: ((self.value as u128 * rhs.value as u128) >> FRAC_BITS).saturating_into(), + _marker: PhantomData, } } } -impl ops::Mul for FPNum { +impl ops::Mul for FixedPoint { type Output = Self; #[inline] @@ -218,23 +231,25 @@ Self { sign_mask: self.sign_mask ^ bool_mask(rhs < 0), value: (self.value as u128 * rhs.abs() as u128).saturating_into(), + _marker: PhantomData, } } } -impl ops::Div for FPNum { +impl ops::Div for FixedPoint { type Output = Self; #[inline] fn div(self, rhs: Self) -> Self { Self { sign_mask: self.sign_mask ^ rhs.sign_mask, - value: (((self.value as u128) << 32) / rhs.value as u128).saturating_into(), + value: (((self.value as u128) << FRAC_BITS) / rhs.value as u128).saturating_into(), + _marker: PhantomData, } } } -impl ops::Div for FPNum { +impl ops::Div for FixedPoint { type Output = Self; #[inline] @@ -242,11 +257,12 @@ Self { sign_mask: self.sign_mask ^ bool_mask(rhs < 0), value: self.value / rhs.abs() as u64, + _marker: PhantomData, } } } -impl ops::Div for FPNum { +impl ops::Div for FixedPoint { type Output = Self; #[inline] @@ -254,6 +270,7 @@ Self { sign_mask: self.sign_mask, value: self.value / rhs as u64, + _marker: PhantomData, } } } @@ -309,6 +326,7 @@ FPNum { sign_mask: self.x_sign_mask as i32 as u64, value: self.x_value, + _marker: PhantomData, } } @@ -317,6 +335,7 @@ FPNum { sign_mask: self.y_sign_mask as i32 as u64, value: self.y_value, + _marker: PhantomData, } } @@ -346,6 +365,7 @@ FPNum { sign_mask: POSITIVE_MASK, value: integral_sqrt_ext(sqr), + _marker: PhantomData, } } } @@ -504,16 +524,17 @@ } #[inline] -pub fn distance(x: T, y: T) -> FPNum +pub fn distance(x: T, y: T) -> FixedPoint where T: Into + std::fmt::Debug, { - let [x_squared, y_squared] = [x, y].map(|i| (i.into().pow(2) as u128).saturating_mul(2^64)); + let [x_squared, y_squared] = [x, y].map(|i| (i.into().pow(2) as u128).saturating_mul(1 << FRAC_BITS << FRAC_BITS)); let sqr: u128 = x_squared.saturating_add(y_squared); - FPNum { + FixedPoint { sign_mask: POSITIVE_MASK, value: integral_sqrt_ext(sqr), + _marker: PhantomData, } } diff -r a5eaeefa4ab3 -r 6633961698ad rust/integral-geometry/src/lib.rs --- a/rust/integral-geometry/src/lib.rs Thu Dec 19 12:43:38 2024 +0100 +++ b/rust/integral-geometry/src/lib.rs Thu Dec 19 14:18:55 2024 +0100 @@ -107,7 +107,7 @@ #[inline] pub fn from_fppoint(p: &FPPoint) -> Self { - Self::new(p.x().round(), p.y().round()) + Self::new(p.x().round() as i32, p.y().round() as i32) } } @@ -614,11 +614,11 @@ self.vertices.insert(edge_index + 1, vertex); } - pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter(&self) -> impl Iterator { (&self.vertices[..self.edges_count()]).iter() } - pub fn iter_mut<'a>(&'a mut self) -> impl Iterator + 'a { + pub fn iter_mut(&mut self) -> impl Iterator { let edges_count = self.edges_count(); let start = self.vertices.as_mut_ptr(); let end = unsafe { start.add(edges_count) };