diff --git a/Cargo.lock b/Cargo.lock index 9a1335e7..c4f00eb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -433,9 +433,9 @@ dependencies = [ [[package]] name = "bnum" -version = "0.13.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119771309b95163ec7aaf79810da82f7cd0599c19722d48b9c03894dca833966" +checksum = "acf40f6d425354fe40ff439c2a4a2733f583e49379eb8601a4c79e50c4a3c579" [[package]] name = "bstr" diff --git a/engine/physics/src/body.rs b/engine/physics/src/body.rs index 275edfd5..f04aabd3 100644 --- a/engine/physics/src/body.rs +++ b/engine/physics/src/body.rs @@ -86,12 +86,12 @@ impl Trajectory pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{ let dt=time-self.time; self.position - +(self.velocity*dt).map(|elem|elem.divide().clamp_1()) - +self.acceleration.map(|elem|(dt*dt*elem/2).divide().clamp_1()) + +(self.velocity*dt).map(|elem|elem.divide().clamp_64()) + +self.acceleration.map(|elem|(dt*dt*elem/2).divide().clamp_64()) } pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{ let dt=time-self.time; - self.velocity+(self.acceleration*dt).map(|elem|elem.divide().clamp_1()) + self.velocity+(self.acceleration*dt).map(|elem|elem.divide().clamp_64()) } pub fn extrapolated_body(&self,time:Time)->Body{ Body::new( diff --git a/engine/physics/src/face_crawler.rs b/engine/physics/src/face_crawler.rs index dc2d9541..2d3ad74d 100644 --- a/engine/physics/src/face_crawler.rs +++ b/engine/physics/src/face_crawler.rs @@ -1,5 +1,7 @@ use crate::model::{into_giga_time,GigaTime}; -use strafesnet_common::integer::{Fixed,Ratio,vec3::Vector3,Planar64Vec3}; +use strafesnet_common::integer::fixed_types::{F64_32,F128_64,F256_128}; +use strafesnet_common::integer::vec3::Vector3; +use strafesnet_common::integer::{Ratio,Planar64Vec3}; use crate::physics::{Time,Trajectory}; use crate::mesh_query::{FEV,DirectedEdge,MeshQuery,MeshTopology}; @@ -65,16 +67,16 @@ where } } -impl,Offset=Fixed<4,128>,Position=Planar64Vec3,Direction=Planar64Vec3>> FEV +impl,Offset=F256_128,Position=Planar64Vec3,Direction=Planar64Vec3>> FEV where // This is hardcoded for MinkowskiMesh lol M::Face:Copy, M::Edge:Copy, M::DirectedEdge:Copy, M::Vert:Copy, - F:core::ops::Mul,Output=Fixed<4,128>>, - >>::Output:core::iter::Sum, - M::Offset:core::ops::Sub<>>::Output>, + F:core::ops::Mul, + >::Output:core::iter::Sum, + M::Offset:core::ops::Sub<>::Output>, { fn next_transition(&self,mesh:&M,trajectory:&Trajectory,lower_bound:Bound,mut upper_bound:Bound)->Transition{ //conflicting derivative means it crosses in the wrong direction. @@ -88,7 +90,7 @@ impl,Offset=Fixed<4,128>,Position=Planar64V let (n,d)=mesh.face_nd(face_id); //TODO: use higher precision d value? //use the mesh transform translation instead of baking it into the d value. - for dt in Fixed::<4,128>::zeroes2((n.dot(trajectory.position)-d)*2,n.dot(trajectory.velocity)*2,n.dot(trajectory.acceleration)){ + for dt in F256_128::zeroes2((n.dot(trajectory.position)-d)*2,n.dot(trajectory.velocity)*2,n.dot(trajectory.acceleration)){ if low(&lower_bound,&dt)&&upp(&dt,&upper_bound)&&n.dot(trajectory.extrapolated_velocity_ratio_dt(dt)).is_negative(){ upper_bound=Bound::Included(dt); best_transition=Transition::Hit(face_id,dt); @@ -103,7 +105,7 @@ impl,Offset=Fixed<4,128>,Position=Planar64V //WARNING: d is moved out of the *2 block because of adding two vertices! //WARNING: precision is swept under the rug! //wrap for speed - for dt in Fixed::<4,128>::zeroes2(n.dot(trajectory.position*2-(mesh.vert(v0)+mesh.vert(v1))).wrap_4(),n.dot(trajectory.velocity).wrap_4()*2,n.dot(trajectory.acceleration).wrap_4()){ + for dt in F256_128::zeroes2(n.dot(trajectory.position*2-(mesh.vert(v0)+mesh.vert(v1))).wrap_256(),n.dot(trajectory.velocity).wrap_256()*2,n.dot(trajectory.acceleration).wrap_256()){ if low(&lower_bound,&dt)&&upp(&dt,&upper_bound)&&n.dot(trajectory.extrapolated_velocity_ratio_dt(dt)).is_negative(){ upper_bound=Bound::Included(dt); best_transition=Transition::Next(FEV::Edge(directed_edge_id.as_undirected()),dt); @@ -126,7 +128,7 @@ impl,Offset=Fixed<4,128>,Position=Planar64V let n=face_n.cross(edge_n)*((i as i64)*2-1); //WARNING yada yada d *2 //wrap for speed - for dt in Fixed::<4,128>::zeroes2(n.dot(delta_pos).wrap_4(),n.dot(trajectory.velocity).wrap_4()*2,n.dot(trajectory.acceleration).wrap_4()){ + for dt in F256_128::zeroes2(n.dot(delta_pos).wrap_256(),n.dot(trajectory.velocity).wrap_256()*2,n.dot(trajectory.acceleration).wrap_256()){ if low(&lower_bound,&dt)&&upp(&dt,&upper_bound)&&n.dot(trajectory.extrapolated_velocity_ratio_dt(dt)).is_negative(){ upper_bound=Bound::Included(dt); best_transition=Transition::Next(FEV::Face(edge_face_id),dt); @@ -138,9 +140,9 @@ impl,Offset=Fixed<4,128>,Position=Planar64V for (i,&vert_id) in edge_verts.as_ref().iter().enumerate(){ //vertex normal gets parity from vert index let n=edge_n*(1-2*(i as i64)); - for dt in Fixed::<2,64>::zeroes2((n.dot(trajectory.position-mesh.vert(vert_id)))*2,n.dot(trajectory.velocity)*2,n.dot(trajectory.acceleration)){ + for dt in F128_64::zeroes2((n.dot(trajectory.position-mesh.vert(vert_id)))*2,n.dot(trajectory.velocity)*2,n.dot(trajectory.acceleration)){ if low(&lower_bound,&dt)&&upp(&dt,&upper_bound)&&n.dot(trajectory.extrapolated_velocity_ratio_dt(dt)).is_negative(){ - let dt=Ratio::new(dt.num.widen_4(),dt.den.widen_4()); + let dt=Ratio::new(dt.num.widen_256(),dt.den.widen_256()); upper_bound=Bound::Included(dt); best_transition=Transition::Next(FEV::Vert(vert_id),dt); break; @@ -154,9 +156,9 @@ impl,Offset=Fixed<4,128>,Position=Planar64V mesh.for_each_vert_edge(vert_id,|directed_edge_id|{ //edge is directed away from vertex, but we want the dot product to turn out negative let n=-mesh.directed_edge_n(directed_edge_id); - for dt in Fixed::<2,64>::zeroes2((n.dot(trajectory.position-mesh.vert(vert_id)))*2,n.dot(trajectory.velocity)*2,n.dot(trajectory.acceleration)){ + for dt in F128_64::zeroes2((n.dot(trajectory.position-mesh.vert(vert_id)))*2,n.dot(trajectory.velocity)*2,n.dot(trajectory.acceleration)){ if low(&lower_bound,&dt)&&upp(&dt,&upper_bound)&&n.dot(trajectory.extrapolated_velocity_ratio_dt(dt)).is_negative(){ - let dt=Ratio::new(dt.num.widen_4(),dt.den.widen_4()); + let dt=Ratio::new(dt.num.widen_256(),dt.den.widen_256()); upper_bound=Bound::Included(dt); best_transition=Transition::Next(FEV::Edge(directed_edge_id.as_undirected()),dt); break; diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 2dfd0878..9aff4e38 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -1,3 +1,4 @@ +use strafesnet_common::integer::fixed_types::{F128_64,F192_96,F256_128}; use strafesnet_common::integer::vec3; use strafesnet_common::integer::vec3::Vector3; use strafesnet_common::integer::{Fixed,Planar64,Planar64Vec3}; @@ -100,35 +101,35 @@ const fn choose_any_direction()->Planar64Vec3{ vec3::X } -fn narrow_dir2(dir:Vector3>)->Planar64Vec3{ +fn narrow_dir2(dir:Vector3)->Planar64Vec3{ if dir==vec3::zero(){ - return dir.narrow_1().unwrap(); + return dir.narrow_64().unwrap(); } - let x=dir.x.as_bits().unsigned_abs().bits(); - let y=dir.y.as_bits().unsigned_abs().bits(); - let z=dir.z.as_bits().unsigned_abs().bits(); + let x=dir.x.as_bits().unsigned_abs().bit_width(); + let y=dir.y.as_bits().unsigned_abs().bit_width(); + let z=dir.z.as_bits().unsigned_abs().bit_width(); let big=x.max(y).max(z); const MAX_BITS:u32=64+31; if MAX_BITS>(big-MAX_BITS) }else{ dir - }.narrow_1().unwrap() + }.narrow_64().unwrap() } -fn narrow_dir3(dir:Vector3>)->Planar64Vec3{ +fn narrow_dir3(dir:Vector3)->Planar64Vec3{ if dir==vec3::zero(){ - return dir.narrow_1().unwrap(); + return dir.narrow_64().unwrap(); } - let x=dir.x.as_bits().unsigned_abs().bits(); - let y=dir.y.as_bits().unsigned_abs().bits(); - let z=dir.z.as_bits().unsigned_abs().bits(); + let x=dir.x.as_bits().unsigned_abs().bit_width(); + let y=dir.y.as_bits().unsigned_abs().bit_width(); + let z=dir.z.as_bits().unsigned_abs().bit_width(); let big=x.max(y).max(z); const MAX_BITS:u32=96+31; if MAX_BITS>(big-MAX_BITS) }else{ dir - }.narrow_1().unwrap() + }.narrow_64().unwrap() } fn reduce1>( @@ -565,8 +566,8 @@ trait Contains{ // convenience type to check if a point is within some threshold of a plane. struct ThickPlane{ point:Planar64Vec3, - normal:Vector3>, - epsilon:Fixed<3,96>, + normal:Vector3, + epsilon:F192_96, } impl ThickPlane{ fn new>(mesh:&M,[v0,v1,v2]:Simplex<3,M::Vert>)->Self{ @@ -577,7 +578,7 @@ impl ThickPlane{ let normal=(p1-p0).cross(p2-p0); // Allow ~ 2*sqrt(3) units of thickness on the plane // This is to account for the variance of two voxels across the longest diagonal - let epsilon=(normal.length()*(Planar64::EPSILON*3)).wrap_3(); + let epsilon=(normal.length()*(Planar64::EPSILON*3)).wrap_192(); Self{point,normal,epsilon} } } @@ -590,7 +591,7 @@ impl Contains for ThickPlane{ struct ThickLine{ point:Planar64Vec3, dir:Planar64Vec3, - epsilon:Fixed<4,128>, + epsilon:F256_128, } impl ThickLine{ fn new>(mesh:&M,[v0,v1]:Simplex<2,M::Vert>)->Self{ @@ -600,7 +601,7 @@ impl ThickLine{ let dir=p1-p0; // Allow ~ 2*sqrt(3) units of thickness on the plane // This is to account for the variance of two voxels across the longest diagonal - let epsilon=(dir.length_squared()*(Planar64::EPSILON*3)).widen_4(); + let epsilon=(dir.length_squared()*(Planar64::EPSILON*3)).widen_256(); Self{point,dir,epsilon} } } @@ -613,7 +614,7 @@ impl Contains for ThickLine{ struct EVFinder<'a,M,C>{ mesh:&'a M, constraint:C, - best_distance_squared:Fixed<2,64>, + best_distance_squared:F128_64, } impl,C:Contains> EVFinder<'_,M,C> @@ -657,7 +658,7 @@ impl,C:Contains> EVFinder<'_,M,C> let distance_squared={ let c=diff.cross(edge_n); //wrap for speed - (c.dot(c)/edge_nn).divide().wrap_2() + (c.dot(c)/edge_nn).divide().wrap_128() }; if distance_squared<=self.best_distance_squared{ best_transition=EV::Edge(directed_edge_id.as_undirected()); diff --git a/engine/physics/src/minkowski.rs b/engine/physics/src/minkowski.rs index bbb87486..37b7f23e 100644 --- a/engine/physics/src/minkowski.rs +++ b/engine/physics/src/minkowski.rs @@ -1,6 +1,8 @@ use core::ops::{Bound,RangeBounds}; -use strafesnet_common::integer::{Planar64Vec3,Ratio,Fixed,vec3::Vector3}; +use strafesnet_common::integer::fixed_types::{F192_96,F256_128,F512_256}; +use strafesnet_common::integer::vec3::Vector3; +use strafesnet_common::integer::{Planar64Vec3,Ratio,Fixed}; use crate::model::into_giga_time; use crate::model::{SubmeshVertId,SubmeshEdgeId,SubmeshDirectedEdgeId,SubmeshFaceId,TransformedMesh,GigaTime}; use crate::mesh_query::{MeshQuery,MeshTopology,DirectedEdge,UndirectedEdge}; @@ -142,7 +144,7 @@ impl MinkowskiMesh<'_>{ //WARNING! d outside of *2 //WARNING: truncated precision //wrap for speed - for dt in Fixed::<4,128>::zeroes2(((n.dot(trajectory.position))*2-d).wrap_4(),n.dot(trajectory.velocity).wrap_4()*2,n.dot(trajectory.acceleration).wrap_4()){ + for dt in F256_128::zeroes2(((n.dot(trajectory.position))*2-d).wrap_256(),n.dot(trajectory.velocity).wrap_256()*2,n.dot(trajectory.acceleration).wrap_256()){ if low(&start_time,&dt)&&upp(&dt,&best_time)&&n.dot(trajectory.extrapolated_velocity_ratio_dt(dt)).is_negative(){ best_time=Bound::Included(dt); best_edge=Some((directed_edge_id,dt)); @@ -159,8 +161,8 @@ impl MinkowskiMesh<'_>{ impl MeshQuery for MinkowskiMesh<'_>{ type Direction=Planar64Vec3; type Position=Planar64Vec3; - type Normal=Vector3>; - type Offset=Fixed<4,128>; + type Normal=Vector3; + type Offset=F256_128; // TODO: relative d fn face_nd(&self,face_id:MinkowskiFace)->(Self::Normal,Self::Offset){ match face_id{ @@ -176,7 +178,7 @@ impl MeshQuery for MinkowskiMesh<'_>{ let n=edge0_n.cross(edge1_n); let e0d=n.dot(self.mesh0.vert(e0v0)+self.mesh0.vert(e0v1)); let e1d=n.dot(self.mesh1.vert(e1v0)+self.mesh1.vert(e1v1)); - ((n*(parity as i64*4-2)).widen_3(),((e0d-e1d)*(parity as i64*2-1)).widen_4()) + ((n*(parity as i64*4-2)).widen_192(),((e0d-e1d)*(parity as i64*2-1)).widen_256()) }, MinkowskiFace::FaceVert(f0,v1)=>{ let (n,d)=self.mesh0.face_nd(f0); @@ -240,7 +242,7 @@ impl MeshTopology for MinkowskiMesh<'_>{ for face_n in &v1f_n{ //add reflected mesh1 faces //wrap for speed - face_normals.push(*face_n-(n*face_n.dot(n)*2/nn).divide().wrap_3()); + face_normals.push(*face_n-(n*face_n.dot(n)*2/nn).divide().wrap_192()); } if is_empty_volume(&face_normals){ f(MinkowskiDirectedEdge::EdgeVert(directed_edge_id,v1)); @@ -255,7 +257,7 @@ impl MeshTopology for MinkowskiMesh<'_>{ // make a set of faces from mesh1's perspective for face_n in &v0f_n{ //wrap for speed - face_normals.push(*face_n-(n*face_n.dot(n)*2/nn).divide().wrap_3()); + face_normals.push(*face_n-(n*face_n.dot(n)*2/nn).divide().wrap_192()); } if is_empty_volume(&face_normals){ f(MinkowskiDirectedEdge::VertEdge(v0,directed_edge_id)); @@ -279,7 +281,7 @@ impl MeshTopology for MinkowskiMesh<'_>{ let &[e1f0,e1f1]=self.mesh1.edge_faces(e1).as_ref(); AsRefHelper([(e1f1,false),(e1f0,true)].map(|(edge_face_id1,face_parity)|{ let mut best_edge=None; - let mut best_d:Ratio,Fixed<8,256>>=Ratio::new(Fixed::ZERO,Fixed::ONE); + let mut best_d:Ratio=Ratio::new(Fixed::ZERO,Fixed::ONE); let edge_face1_n=self.mesh1.face_nd(edge_face_id1).0; let edge_face1_nn=edge_face1_n.dot(edge_face1_n); for &directed_edge_id0 in &v0e{ @@ -313,7 +315,7 @@ impl MeshTopology for MinkowskiMesh<'_>{ let &[e0f0,e0f1]=self.mesh0.edge_faces(e0).as_ref(); AsRefHelper([(e0f0,true),(e0f1,false)].map(|(edge_face_id0,face_parity)|{ let mut best_edge=None; - let mut best_d:Ratio,Fixed<8,256>>=Ratio::new(Fixed::ZERO,Fixed::ONE); + let mut best_d:Ratio=Ratio::new(Fixed::ZERO,Fixed::ONE); let edge_face0_n=self.mesh0.face_nd(edge_face_id0).0; let edge_face0_nn=edge_face0_n.dot(edge_face0_n); for &directed_edge_id1 in &v1e{ @@ -375,7 +377,7 @@ impl MeshTopology for MinkowskiMesh<'_>{ } } -fn is_empty_volume(normals:&[Vector3>])->bool{ +fn is_empty_volume(normals:&[Vector3])->bool{ let len=normals.len(); for i in 0..len-1{ for j in i+1..len{ @@ -402,6 +404,6 @@ fn is_empty_volume(normals:&[Vector3>])->bool{ #[test] fn test_is_empty_volume(){ use strafesnet_common::integer::vec3; - assert!(!is_empty_volume(&[vec3::X.widen_3(),vec3::Y.widen_3(),vec3::Z.widen_3()])); - assert!(is_empty_volume(&[vec3::X.widen_3(),vec3::Y.widen_3(),vec3::Z.widen_3(),vec3::NEG_X.widen_3()])); + assert!(!is_empty_volume(&[vec3::X.widen_192(),vec3::Y.widen_192(),vec3::Z.widen_192()])); + assert!(is_empty_volume(&[vec3::X.widen_192(),vec3::Y.widen_192(),vec3::Z.widen_192(),vec3::NEG_X.widen_192()])); } diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index 8c8b6822..c7ceee12 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -1,4 +1,5 @@ use std::collections::{HashSet,HashMap}; +use strafesnet_common::integer::fixed_types::{F128_64,F192_96,F256_128}; use strafesnet_common::integer::vec3::Vector3; use strafesnet_common::model::{self,MeshId,PolygonIter}; use strafesnet_common::integer::{self,vec3,Fixed,Planar64,Planar64Vec3,Ratio}; @@ -349,8 +350,8 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{ } //assume face hash is stable, and there are no flush faces... let face=Face{ - normal:(normal/len as i64).divide().narrow_1().unwrap(), - dot:(dot/(len*len) as i64).narrow_1().unwrap(), + normal:(normal/len as i64).divide().narrow_64().unwrap(), + dot:(dot/(len*len) as i64).narrow_64().unwrap(), }; let face_id=*face_id_from_face.entry(face).or_insert_with(||{ let face_id=MeshFaceId::new(faces.len() as u32); @@ -461,8 +462,8 @@ impl MeshTopology for PhysicsMeshView<'_>{ #[derive(Debug)] pub struct PhysicsMeshTransform{ pub vertex:integer::Planar64Affine3, - pub normal:integer::mat3::Matrix3>, - pub det:Fixed<3,96>, + pub normal:integer::mat3::Matrix3, + pub det:F192_96, } impl PhysicsMeshTransform{ pub fn new(transform:integer::Planar64Affine3)->Self{ @@ -489,15 +490,15 @@ impl TransformedMesh<'_>{ transform, } } - pub fn verts<'a>(&'a self)->impl Iterator>>+'a{ + pub fn verts<'a>(&'a self)->impl Iterator>+'a{ self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos)) } } impl MeshQuery for TransformedMesh<'_>{ type Direction=Planar64Vec3; type Position=Planar64Vec3; - type Normal=Vector3>; - type Offset=Fixed<4,128>; + type Normal=Vector3; + type Offset=F256_128; fn face_nd(&self,face_id:SubmeshFaceId)->(Self::Normal,Self::Offset){ let (n,d)=self.view.face_nd(face_id); let transformed_n=self.transform.normal*n; @@ -506,7 +507,7 @@ impl MeshQuery for TransformedMesh<'_>{ } fn vert(&self,vert_id:SubmeshVertId)->Planar64Vec3{ // wrap for speed - self.transform.vertex.transform_point3(self.view.vert(vert_id)).wrap_1() + self.transform.vertex.transform_point3(self.view.vert(vert_id)).wrap_64() } fn hint_point(&self)->Planar64Vec3{ self.transform.vertex.translation @@ -562,8 +563,8 @@ impl MeshTopology for TransformedMesh<'_>{ } } -pub type GigaTime=Ratio,Fixed<4,128>>; +pub type GigaTime=Ratio; pub fn into_giga_time(time:Time,relative_to:Time)->GigaTime{ let r=(time-relative_to).to_ratio(); - Ratio::new(r.num.widen_4(),r.den.widen_4()) + Ratio::new(r.num.widen_256(),r.den.widen_256()) } diff --git a/engine/physics/src/physics.rs b/engine/physics/src/physics.rs index d68625d5..31f70b3e 100644 --- a/engine/physics/src/physics.rs +++ b/engine/physics/src/physics.rs @@ -129,8 +129,8 @@ impl TransientAcceleration{ }else{ //normal friction acceleration is clippedAcceleration.dot(normal)*friction TransientAcceleration::Reachable{ - acceleration:target_diff.with_length(accel).divide().wrap_1(), - time:time+Time::from((target_diff.length()/accel).divide().clamp_1()) + acceleration:target_diff.with_length(accel).divide().wrap_64(), + time:time+Time::from((target_diff.length()/accel).divide().clamp_64()) } } } @@ -428,7 +428,7 @@ impl HitboxMesh{ let transform=PhysicsMeshTransform::new(transform); let transformed_mesh=TransformedMesh::new(mesh.complete_mesh_view(),&transform); for vert in transformed_mesh.verts(){ - aabb.grow(vert.narrow_1().unwrap()); + aabb.grow(vert.narrow_64().unwrap()); } Self{ halfsize:aabb.size()>>1, @@ -481,12 +481,12 @@ impl StyleHelper for StyleModifiers{ } fn get_y_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{ - (camera.rotation_y()*self.get_control_dir(controls)).wrap_1() + (camera.rotation_y()*self.get_control_dir(controls)).wrap_64() } fn get_propulsion_control_dir(&self,camera:&PhysicsCamera,controls:Controls)->Planar64Vec3{ //don't interpolate this! discrete mouse movement, constant acceleration - (camera.rotation()*self.get_control_dir(controls)).wrap_1() + (camera.rotation()*self.get_control_dir(controls)).wrap_64() } fn calculate_mesh(&self)->HitboxMesh{ let mesh=match self.hitbox.mesh{ @@ -1118,7 +1118,7 @@ impl PhysicsData{ let mut aabb=aabb::Aabb::default(); let transformed_mesh=TransformedMesh::new(view,transform); for v in transformed_mesh.verts(){ - aabb.grow(v.narrow_1().unwrap()); + aabb.grow(v.narrow_64().unwrap()); } (ConvexMeshId{ model_id, @@ -1251,7 +1251,7 @@ fn contact_normal( let minkowski=MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh()); // TODO: normalize to i64::MAX>>1 // wrap for speed - minkowski.face_nd(face_id).0.wrap_1() + minkowski.face_nd(face_id).0.wrap_64() } fn recalculate_touching( @@ -1391,7 +1391,7 @@ fn teleport_to_spawn( const EPSILON:Planar64=Planar64::raw((1<<32)/16); let transform=models.get_model_transform(spawn_model_id).ok_or(TeleportToSpawnError::NoModel)?; //TODO: transform.vertex.matrix3.col(1)+transform.vertex.translation - let point=transform.vertex.transform_point3(vec3::Y).clamp_1()+Planar64Vec3::new([Planar64::ZERO,style.hitbox.halfsize.y+EPSILON,Planar64::ZERO]); + let point=transform.vertex.transform_point3(vec3::Y).clamp_64()+Planar64Vec3::new([Planar64::ZERO,style.hitbox.halfsize.y+EPSILON,Planar64::ZERO]); teleport(point,move_state,body,touching,run,mode_state,Some(mode),models,hitbox_mesh,bvh,style,camera,input_state,time); Ok(()) } @@ -1555,7 +1555,7 @@ fn collision_start_contact( Some(gameplay_attributes::ContactingBehaviour::Surf)=>(), Some(gameplay_attributes::ContactingBehaviour::Cling)=>println!("Unimplemented!"), &Some(gameplay_attributes::ContactingBehaviour::Elastic(elasticity))=>{ - let reflected_velocity=body.velocity+((body.velocity-incident_velocity)*Planar64::raw(elasticity as i64+1)).wrap_1(); + let reflected_velocity=body.velocity+((body.velocity-incident_velocity)*Planar64::raw(elasticity as i64+1)).wrap_64(); set_velocity(body,touching,models,hitbox_mesh,reflected_velocity); }, Some(gameplay_attributes::ContactingBehaviour::Ladder(contacting_ladder))=> @@ -1809,7 +1809,7 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim // manually advance time let extrapolated_body=state.body.with_acceleration(state.acceleration(data)).extrapolated_body(state.time); let camera_mat=state.camera.simulate_move_rotation_y(state.input_state.lerp_delta(state.time).x); - if let Some(ticked_velocity)=strafe_settings.tick_velocity(extrapolated_body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE).divide().wrap_1()){ + if let Some(ticked_velocity)=strafe_settings.tick_velocity(extrapolated_body.velocity,(camera_mat*control_dir).with_length(Planar64::ONE).divide().wrap_64()){ state.body=extrapolated_body; //this is wrong but will work ig //need to note which push planes activate in push solve and keep those diff --git a/engine/physics/src/push_solve.rs b/engine/physics/src/push_solve.rs index 896e39cb..7d54ca3e 100644 --- a/engine/physics/src/push_solve.rs +++ b/engine/physics/src/push_solve.rs @@ -1,3 +1,4 @@ +use strafesnet_common::integer::fixed_types::{F64_32,F128_64,F192_96,F256_128,F320_160}; use strafesnet_common::integer::vec3::{self,Vector3}; use strafesnet_common::integer::{Fixed,Planar64Vec3,Ratio}; use strafesnet_common::ray::Ray; @@ -12,7 +13,7 @@ use strafesnet_common::ray::Ray; type Conts<'a>=arrayvec::ArrayVec<&'a Contact,4>; // hack to allow comparing ratios to zero -const RATIO_ZERO:Ratio,Fixed<1,32>>=Ratio::new(Fixed::ZERO,Fixed::EPSILON); +const RATIO_ZERO:Ratio=Ratio::new(Fixed::ZERO,Fixed::EPSILON); /// Information about a contact restriction #[derive(Debug,PartialEq)] @@ -29,17 +30,17 @@ impl Contact{ normal:self.normal, } } - fn relative_dot(&self,direction:Planar64Vec3)->Fixed<2,64>{ + fn relative_dot(&self,direction:Planar64Vec3)->F128_64{ (direction-self.velocity).dot(self.normal) } /// Calculate the time of intersection. (previously get_touch_time) - fn solve(&self,ray:&Ray)->Ratio,Fixed<2,64>>{ + fn solve(&self,ray:&Ray)->Ratio{ (self.position-ray.origin).dot(self.normal)/(ray.direction-self.velocity).dot(self.normal) } } //note that this is horrible with fixed point arithmetic -fn solve1(c0:&Contact)->Option>,Fixed<2,64>>>{ +fn solve1(c0:&Contact)->Option,F128_64>>{ let det=c0.normal.dot(c0.velocity); if det.abs()==Fixed::ZERO{ return None; @@ -47,7 +48,7 @@ fn solve1(c0:&Contact)->Option>,Fixed<2,64>>>{ let d0=c0.normal.dot(c0.position); Some(c0.normal*d0/det) } -fn solve2(c0:&Contact,c1:&Contact)->Option>,Fixed<4,128>>>{ +fn solve2(c0:&Contact,c1:&Contact)->Option,F256_128>>{ let u0_u1=c0.velocity.cross(c1.velocity); let n0_n1=c0.normal.cross(c1.normal); let det=u0_u1.dot(n0_n1); @@ -58,7 +59,7 @@ fn solve2(c0:&Contact,c1:&Contact)->Option>,Fixed<4,1 let d1=c1.normal.dot(c1.position); Some((c1.normal.cross(u0_u1)*d0+u0_u1.cross(c0.normal)*d1)/det) } -fn solve3(c0:&Contact,c1:&Contact,c2:&Contact)->Option>,Fixed<3,96>>>{ +fn solve3(c0:&Contact,c1:&Contact,c2:&Contact)->Option,F192_96>>{ let n0_n1=c0.normal.cross(c1.normal); let det=c2.normal.dot(n0_n1); if det.abs()==Fixed::ZERO{ @@ -70,7 +71,7 @@ fn solve3(c0:&Contact,c1:&Contact,c2:&Contact)->OptionOption<[Ratio,Fixed<2,64>>;1]>{ +fn decompose1(point:Planar64Vec3,u0:Planar64Vec3)->Option<[Ratio;1]>{ let det=u0.dot(u0); if det==Fixed::ZERO{ return None; @@ -78,7 +79,7 @@ fn decompose1(point:Planar64Vec3,u0:Planar64Vec3)->Option<[Ratio,Fix let s0=u0.dot(point)/det; Some([s0]) } -fn decompose2(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3)->Option<[Ratio,Fixed<4,128>>;2]>{ +fn decompose2(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3)->Option<[Ratio;2]>{ let u0_u1=u0.cross(u1); let det=u0_u1.dot(u0_u1); if det==Fixed::ZERO{ @@ -88,7 +89,7 @@ fn decompose2(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3)->Option<[Ratio let s1=u0_u1.dot(u0.cross(point))/det; Some([s0,s1]) } -fn decompose3(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3,u2:Planar64Vec3)->Option<[Ratio,Fixed<3,96>>;3]>{ +fn decompose3(point:Planar64Vec3,u0:Planar64Vec3,u1:Planar64Vec3,u2:Planar64Vec3)->Option<[Ratio;3]>{ let det=u0.cross(u1).dot(u2); if det==Fixed::ZERO{ return None; @@ -151,18 +152,18 @@ const fn get_push_ray_0(point:Planar64Vec3)->Ray{ } fn get_push_ray_1(point:Planar64Vec3,c0:&Contact)->Option{ //wrap for speed - let direction=solve1(c0)?.divide().wrap_1(); + let direction=solve1(c0)?.divide().wrap_64(); let [s0]=decompose1(direction,c0.velocity)?; if s0.lt_ratio(RATIO_ZERO){ return None; } let origin=point+solve1( &c0.relative_to(point), - )?.divide().wrap_1(); + )?.divide().wrap_64(); Some(Ray{origin,direction}) } fn get_push_ray_2(point:Planar64Vec3,c0:&Contact,c1:&Contact)->Option{ - let direction=solve2(c0,c1)?.divide().wrap_1(); + let direction=solve2(c0,c1)?.divide().wrap_64(); let [s0,s1]=decompose2(direction,c0.velocity,c1.velocity)?; if s0.lt_ratio(RATIO_ZERO)||s1.lt_ratio(RATIO_ZERO){ return None; @@ -170,11 +171,11 @@ fn get_push_ray_2(point:Planar64Vec3,c0:&Contact,c1:&Contact)->Option{ let origin=point+solve2( &c0.relative_to(point), &c1.relative_to(point), - )?.divide().wrap_1(); + )?.divide().wrap_64(); Some(Ray{origin,direction}) } fn get_push_ray_3(point:Planar64Vec3,c0:&Contact,c1:&Contact,c2:&Contact)->Option{ - let direction=solve3(c0,c1,c2)?.divide().wrap_1(); + let direction=solve3(c0,c1,c2)?.divide().wrap_64(); let [s0,s1,s2]=decompose3(direction,c0.velocity,c1.velocity,c2.velocity)?; if s0.lt_ratio(RATIO_ZERO)||s1.lt_ratio(RATIO_ZERO)||s2.lt_ratio(RATIO_ZERO){ return None; @@ -183,7 +184,7 @@ fn get_push_ray_3(point:Planar64Vec3,c0:&Contact,c1:&Contact,c2:&Contact)->Optio &c0.relative_to(point), &c1.relative_to(point), &c2.relative_to(point), - )?.divide().wrap_1(); + )?.divide().wrap_64(); Some(Ray{origin,direction}) } @@ -272,7 +273,7 @@ fn get_best_push_ray_and_conts<'a>( } } -fn get_first_touch<'a>(contacts:&'a [Contact],ray:&Ray,conts:&Conts)->Option<(Ratio,Fixed<2,64>>,&'a Contact)>{ +fn get_first_touch<'a>(contacts:&'a [Contact],ray:&Ray,conts:&Conts)->Option<(Ratio,&'a Contact)>{ contacts.iter() .filter(|&contact| !conts.iter().any(|&c|std::ptr::eq(c,contact)) diff --git a/lib/bsp_loader/src/brush.rs b/lib/bsp_loader/src/brush.rs index 9e431086..ba883f5b 100644 --- a/lib/bsp_loader/src/brush.rs +++ b/lib/bsp_loader/src/brush.rs @@ -1,21 +1,22 @@ -use strafesnet_common::integer::Planar64; use strafesnet_common::{model,integer}; -use strafesnet_common::integer::{vec3::Vector3,Fixed,Ratio}; +use strafesnet_common::integer::fixed_types::F192_96; +use strafesnet_common::integer::vec3::Vector3; +use strafesnet_common::integer::{Planar64,Planar64Vec3,Ratio}; use crate::{valve_transform_normal,valve_transform_dist}; #[derive(Hash,Eq,PartialEq)] struct Face{ - normal:integer::Planar64Vec3, + normal:Planar64Vec3, dot:Planar64, } #[derive(Debug)] struct Faces{ - faces:Vec>, + faces:Vec>, } -fn solve3(c0:&Face,c1:&Face,c2:&Face)->Option>,Fixed<3,96>>>{ +fn solve3(c0:&Face,c1:&Face,c2:&Face)->Option,F192_96>>{ let n0_n1=c0.normal.cross(c1.normal); let det=c2.normal.dot(n0_n1); if det.abs().is_zero(){ @@ -82,12 +83,12 @@ fn planes_to_faces(face_list:std::collections::HashSet)->Result)->Result)->Result)->Result>)->model::Mesh{ +pub fn faces_to_mesh(faces:Vec>)->model::Mesh{ // generate the mesh let mut mb=model::MeshBuilder::new(); let color=mb.acquire_color_id(glam::Vec4::ONE); diff --git a/lib/common/src/aabb.rs b/lib/common/src/aabb.rs index af3e2596..6c0d9de0 100644 --- a/lib/common/src/aabb.rs +++ b/lib/common/src/aabb.rs @@ -62,7 +62,7 @@ impl Aabb{ self.min.map_zip(self.max,|(min,max)|min.midpoint(max)) } #[inline] - pub fn area_weight(&self)->fixed_wide::fixed::Fixed<2,64>{ + pub fn area_weight(&self)->fixed_wide::types::F128_64{ let d=self.max-self.min; d.x*d.y+d.y*d.z+d.z*d.x } diff --git a/lib/common/src/gameplay_style.rs b/lib/common/src/gameplay_style.rs index 464c99a8..71861d44 100644 --- a/lib/common/src/gameplay_style.rs +++ b/lib/common/src/gameplay_style.rs @@ -66,7 +66,7 @@ impl JumpImpulse{ _mass:Planar64, )->Planar64Vec3{ match self{ - &JumpImpulse::Time(time)=>velocity-(*gravity*time).map(|t|t.divide().clamp_1()), + &JumpImpulse::Time(time)=>velocity-(*gravity*time).map(|t|t.divide().clamp_64()), &JumpImpulse::Height(height)=>{ //height==-v.y*v.y/(2*g.y); //use energy to determine max height @@ -74,10 +74,10 @@ impl JumpImpulse{ let g=gg.sqrt(); let v_g=gravity.dot(velocity); //do it backwards - let radicand=v_g*v_g+(g*height*2).widen_4(); - velocity-(*gravity*(radicand.sqrt().wrap_2()+v_g)/gg).divide().clamp_1() + let radicand=v_g*v_g+(g*height*2).widen_256(); + velocity-(*gravity*(radicand.sqrt().wrap_128()+v_g)/gg).divide().clamp_64() }, - &JumpImpulse::Linear(jump_speed)=>velocity+(jump_dir*jump_speed/jump_dir.length()).divide().clamp_1(), + &JumpImpulse::Linear(jump_speed)=>velocity+(jump_dir*jump_speed/jump_dir.length()).divide().clamp_64(), &JumpImpulse::Energy(_energy)=>{ //calculate energy //let e=gravity.dot(velocity); @@ -91,10 +91,10 @@ impl JumpImpulse{ pub fn get_jump_deltav(&self,gravity:&Planar64Vec3,mass:Planar64)->Planar64{ //gravity.length() is actually the proper calculation because the jump is always opposite the gravity direction match self{ - &JumpImpulse::Time(time)=>(gravity.length().wrap_1()*time/2).divide().clamp_1(), - &JumpImpulse::Height(height)=>(gravity.length()*height*2).sqrt().wrap_1(), + &JumpImpulse::Time(time)=>(gravity.length().wrap_64()*time/2).divide().clamp_64(), + &JumpImpulse::Height(height)=>(gravity.length()*height*2).sqrt().wrap_64(), &JumpImpulse::Linear(deltav)=>deltav, - &JumpImpulse::Energy(energy)=>(energy.sqrt()*2/mass.sqrt()).divide().clamp_1(), + &JumpImpulse::Energy(energy)=>(energy.sqrt()*2/mass.sqrt()).divide().clamp_64(), } } } @@ -126,10 +126,10 @@ impl JumpSettings{ None=>rel_velocity, }; let j=boost_vel.dot(jump_dir); - let js=jump_speed.widen_2(); + let js=jump_speed.widen_128(); if jrel_velocity, }; let j=boost_vel.dot(jump_dir); - let js=jump_speed.widen_2(); + let js=jump_speed.widen_128(); if j{ @@ -159,10 +159,10 @@ impl JumpSettings{ None=>rel_velocity, }; let boost_dot=boost_vel.dot(jump_dir); - let js=jump_speed.widen_2(); + let js=jump_speed.widen_128(); if boost_dotbooster.boost(rel_velocity), None=>rel_velocity, }; - boost_vel+jump_dir.with_length(jump_speed).divide().wrap_1() + boost_vel+jump_dir.with_length(jump_speed).divide().wrap_64() }, } } @@ -267,9 +267,9 @@ pub struct StrafeSettings{ impl StrafeSettings{ pub fn tick_velocity(&self,velocity:Planar64Vec3,control_dir:Planar64Vec3)->Option{ let d=velocity.dot(control_dir); - let mv=self.mv.widen_2(); + let mv=self.mv.widen_128(); match dSome(velocity+(control_dir*self.air_accel_limit.map_or(mv-d,|limit|limit.widen_2().min(mv-d))).wrap_1()), + true=>Some(velocity+(control_dir*self.air_accel_limit.map_or(mv-d,|limit|limit.widen_128().min(mv-d))).wrap_64()), false=>None, } } @@ -290,7 +290,7 @@ pub struct PropulsionSettings{ } impl PropulsionSettings{ pub fn acceleration(&self,control_dir:Planar64Vec3)->Planar64Vec3{ - (control_dir*self.magnitude).clamp_1() + (control_dir*self.magnitude).clamp_64() } } @@ -310,13 +310,13 @@ pub struct WalkSettings{ impl WalkSettings{ pub fn accel(&self,target_diff:Planar64Vec3,gravity:Planar64Vec3)->Planar64{ //TODO: fallible walk accel - let diff_len=target_diff.length().wrap_1(); + let diff_len=target_diff.length().wrap_64(); let friction=if diff_lenPlanar64Vec3{ if control_dir==crate::integer::vec3::zero(){ @@ -332,7 +332,7 @@ impl WalkSettings{ if cr==crate::integer::vec3::zero(){ crate::integer::vec3::zero() }else{ - (cr.cross(normal)*self.accelerate.topspeed/((nn*(nnmm-dd)).sqrt())).divide().clamp_1() + (cr.cross(normal)*self.accelerate.topspeed/((nn*(nnmm-dd)).sqrt())).divide().clamp_64() } }else{ crate::integer::vec3::zero() @@ -341,7 +341,7 @@ impl WalkSettings{ pub fn is_slope_walkable(&self,normal:Planar64Vec3,up:Planar64Vec3)->bool{ //normal is not guaranteed to be unit length let ny=normal.dot(up); - let h=normal.length().wrap_1(); + let h=normal.length().wrap_64(); //remember this is a normal vector ny.is_positive()&&h*self.surf_dotSelf{ Self{ - halfsize:((int3(33,73,33)>>1)*VALVE_SCALE).narrow_1().unwrap(), + halfsize:((int3(33,73,33)>>1)*VALVE_SCALE).narrow_64().unwrap(), mesh:HitboxMesh::Box, } } @@ -538,11 +538,11 @@ impl StyleModifiers{ tick_rate:Ratio64::new(100,AbsoluteTime::ONE_SECOND.get() as u64).unwrap(), }), jump:Some(JumpSettings{ - impulse:JumpImpulse::Height((int(52)*VALVE_SCALE).narrow_1().unwrap()), + impulse:JumpImpulse::Height((int(52)*VALVE_SCALE).narrow_64().unwrap()), calculation:JumpCalculation::JumpThenBoost, limit_minimum:true, }), - gravity:(int3(0,-800,0)*VALVE_SCALE).narrow_1().unwrap(), + gravity:(int3(0,-800,0)*VALVE_SCALE).narrow_64().unwrap(), mass:int(1), rocket:None, walk:Some(WalkSettings{ @@ -565,7 +565,7 @@ impl StyleModifiers{ magnitude:int(12),//? }), hitbox:Hitbox::source(), - camera_offset:((int3(0,64,0)-(int3(0,73,0)>>1))*VALVE_SCALE).narrow_1().unwrap(), + camera_offset:((int3(0,64,0)-(int3(0,73,0)>>1))*VALVE_SCALE).narrow_64().unwrap(), } } pub fn source_surf()->Self{ @@ -574,16 +574,16 @@ impl StyleModifiers{ controls_mask_state:Controls::all(), strafe:Some(StrafeSettings{ enable:ControlsActivation::full_2d(), - air_accel_limit:Some((int(150)*66*VALVE_SCALE).narrow_1().unwrap()), + air_accel_limit:Some((int(150)*66*VALVE_SCALE).narrow_64().unwrap()), mv:Planar64::raw(30<<28), tick_rate:Ratio64::new(66,AbsoluteTime::ONE_SECOND.get() as u64).unwrap(), }), jump:Some(JumpSettings{ - impulse:JumpImpulse::Height((int(52)*VALVE_SCALE).narrow_1().unwrap()), + impulse:JumpImpulse::Height((int(52)*VALVE_SCALE).narrow_64().unwrap()), calculation:JumpCalculation::JumpThenBoost, limit_minimum:true, }), - gravity:(int3(0,-800,0)*VALVE_SCALE).narrow_1().unwrap(), + gravity:(int3(0,-800,0)*VALVE_SCALE).narrow_64().unwrap(), mass:int(1), rocket:None, walk:Some(WalkSettings{ @@ -606,7 +606,7 @@ impl StyleModifiers{ magnitude:int(12),//? }), hitbox:Hitbox::source(), - camera_offset:((int3(0,64,0)-(int3(0,73,0)>>1))*VALVE_SCALE).narrow_1().unwrap(), + camera_offset:((int3(0,64,0)-(int3(0,73,0)>>1))*VALVE_SCALE).narrow_64().unwrap(), } } } diff --git a/lib/common/src/integer.rs b/lib/common/src/integer.rs index 33f9d2a6..dd875228 100644 --- a/lib/common/src/integer.rs +++ b/lib/common/src/integer.rs @@ -1,6 +1,12 @@ pub use fixed_wide::fixed::*; pub use ratio_ops::ratio::{Ratio,Divide,Parity}; +pub mod fixed_types{ + pub use fixed_wide::types::*; +} + +use fixed_wide::types::F128_64; + //integer units /// specific example of a "default" time type @@ -68,7 +74,7 @@ impl Time{ impl From for Time{ #[inline] fn from(value:Planar64)->Self{ - Self::raw((value*Planar64::raw(1_000_000_000)).clamp_1().to_raw()) + Self::raw((value*Planar64::raw(1_000_000_000)).clamp_64().to_raw()) } } impl From> for Ratio{ @@ -134,10 +140,10 @@ impl_time_additive_assign_operator!(core::ops::AddAssign,add_assign); impl_time_additive_assign_operator!(core::ops::SubAssign,sub_assign); impl_time_additive_assign_operator!(core::ops::RemAssign,rem_assign); impl std::ops::Mul for Time{ - type Output=Ratio,Fixed<2,64>>; + type Output=Ratio; #[inline] fn mul(self,rhs:Self)->Self::Output{ - Ratio::new(Fixed::raw(self.0)*Fixed::raw(rhs.0),Fixed::raw_digit(1_000_000_000i64.pow(2))) + Ratio::new(Fixed::raw(self.0)*Fixed::raw(rhs.0),Fixed::from_u64(1_000_000_000u64.pow(2))) } } macro_rules! impl_time_i64_rhs_operator { @@ -156,7 +162,7 @@ impl_time_i64_rhs_operator!(Mul,mul); impl_time_i64_rhs_operator!(Shr,shr); impl_time_i64_rhs_operator!(Shl,shl); impl core::ops::Mul> for Planar64{ - type Output=Ratio,Planar64>; + type Output=Ratio; #[inline] fn mul(self,rhs:Time)->Self::Output{ Ratio::new(self*Fixed::raw(rhs.0),Planar64::raw(1_000_000_000)) @@ -177,6 +183,7 @@ impl From> for f64{ #[cfg(test)] mod test_time{ use super::*; + use fixed_wide::types::F64_32; type Time=AbsoluteTime; #[test] fn time_from_planar64(){ @@ -191,13 +198,13 @@ mod test_time{ #[test] fn time_squared(){ let a=Time::from_secs(2); - assert_eq!(a*a,Ratio::new(Fixed::<2,64>::raw_digit(1_000_000_000i64.pow(2))*4,Fixed::<2,64>::raw_digit(1_000_000_000i64.pow(2)))); + assert_eq!(a*a,Ratio::new(F128_64::from_u64(1_000_000_000u64.pow(2))*4,F128_64::from_u64(1_000_000_000u64.pow(2)))); } #[test] fn time_times_planar64(){ let a=Time::from_secs(2); let b=Planar64::from(2); - assert_eq!(b*a,Ratio::new(Fixed::<2,64>::raw_digit(1_000_000_000*(1<<32))<<2,Fixed::<1,32>::raw_digit(1_000_000_000))); + assert_eq!(b*a,Ratio::new(F128_64::from_u64(1_000_000_000*(1<<32))<<2,F64_32::from_u64(1_000_000_000))); } } @@ -565,8 +572,8 @@ fn angle_sin_cos(){ println!("cordic s={} c={}",(s/h).divide(),(c/h).divide()); let (fs,fc)=f.sin_cos(); println!("float s={} c={}",fs,fc); - assert!(close_enough((c/h).divide().wrap_1(),Planar64::raw((fc*((1u64<<32) as f64)) as i64))); - assert!(close_enough((s/h).divide().wrap_1(),Planar64::raw((fs*((1u64<<32) as f64)) as i64))); + assert!(close_enough((c/h).divide().wrap_64(),Planar64::raw((fc*((1u64<<32) as f64)) as i64))); + assert!(close_enough((s/h).divide().wrap_64(),Planar64::raw((fs*((1u64<<32) as f64)) as i64))); } test_angle(1.0); test_angle(std::f64::consts::PI/4.0); @@ -598,7 +605,7 @@ impl TryFrom<[f32;3]> for Unit32Vec3{ */ pub type Planar64TryFromFloatError=FixedFromFloatError; -pub type Planar64=fixed_wide::types::I32F32; +pub type Planar64=fixed_wide::types::F64_32; pub type Planar64Vec3=linear_ops::types::Vector3; pub type Planar64Mat3=linear_ops::types::Matrix3; pub mod vec3{ @@ -677,8 +684,8 @@ pub mod mat3{ let (yc,ys)=y.cos_sin(); Planar64Mat3::from_cols([ Planar64Vec3::new([xc,Planar64::ZERO,-xs]), - Planar64Vec3::new([(xs*ys).wrap_1(),yc,(xc*ys).wrap_1()]), - Planar64Vec3::new([(xs*yc).wrap_1(),-ys,(xc*yc).wrap_1()]), + Planar64Vec3::new([(xs*ys).wrap_64(),yc,(xc*ys).wrap_64()]), + Planar64Vec3::new([(xs*yc).wrap_64(),-ys,(xc*yc).wrap_64()]), ]) } #[inline] @@ -719,8 +726,8 @@ impl Planar64Affine3{ } } #[inline] - pub fn transform_point3(&self,point:Planar64Vec3)->vec3::Vector3>{ - self.translation.widen_2()+self.matrix3*point + pub fn transform_point3(&self,point:Planar64Vec3)->vec3::Vector3{ + self.translation.widen_128()+self.matrix3*point } } impl Into for Planar64Affine3{ diff --git a/lib/fixed_wide/Cargo.toml b/lib/fixed_wide/Cargo.toml index 0cc0d744..3264c73d 100644 --- a/lib/fixed_wide/Cargo.toml +++ b/lib/fixed_wide/Cargo.toml @@ -14,7 +14,7 @@ wide-mul=[] zeroes=["dep:arrayvec"] [dependencies] -bnum = "0.13.0" +bnum = "0.14.3" arrayvec = { version = "0.7.6", optional = true } paste = "1.0.15" ratio_ops = { workspace = true, optional = true } diff --git a/lib/fixed_wide/src/fixed.rs b/lib/fixed_wide/src/fixed.rs index 055f671e..2d5e9fe1 100644 --- a/lib/fixed_wide/src/fixed.rs +++ b/lib/fixed_wide/src/fixed.rs @@ -1,54 +1,58 @@ -use bnum::{BInt,cast::As}; +use bnum::{Int,cast::As,n}; -const BNUM_DIGIT_WIDTH:usize=64; +pub(crate)const BNUM_DIGIT_WIDTH:usize=8; +const DIGIT_SHIFT:u32=BNUM_DIGIT_WIDTH.ilog2(); #[derive(Clone,Copy,Default,Hash,PartialEq,Eq,PartialOrd,Ord)] /// A Fixed point number for which multiply operations widen the bits in the output. (when the wide-mul feature is enabled) -/// N is the number of u64s to use -/// F is the number of fractional bits (always N*32 lol) +/// N is the number of u8s to use +/// F is the number of fractional bits (currently always N*8/2) pub struct Fixed{ - bits:BInt<{N}>, + bits:Int, } impl Fixed{ - pub const MAX:Self=Self::from_bits(BInt::::MAX); - pub const MIN:Self=Self::from_bits(BInt::::MIN); - pub const ZERO:Self=Self::from_bits(BInt::::ZERO); - pub const EPSILON:Self=Self::from_bits(BInt::::ONE); - pub const NEG_EPSILON:Self=Self::from_bits(BInt::::NEG_ONE); - pub const ONE:Self=Self::from_bits(BInt::::ONE.shl(F as u32)); - pub const TWO:Self=Self::from_bits(BInt::::TWO.shl(F as u32)); - pub const HALF:Self=Self::from_bits(BInt::::ONE.shl(F as u32-1)); - pub const NEG_ONE:Self=Self::from_bits(BInt::::NEG_ONE.shl(F as u32)); - pub const NEG_TWO:Self=Self::from_bits(BInt::::NEG_TWO.shl(F as u32)); - pub const NEG_HALF:Self=Self::from_bits(BInt::::NEG_ONE.shl(F as u32-1)); + pub const MAX:Self=Self::from_bits(Int::::MAX); + pub const MIN:Self=Self::from_bits(Int::::MIN); + pub const ZERO:Self=Self::from_bits(n!(0)); + pub const EPSILON:Self=Self::from_bits(n!(1)); + pub const NEG_EPSILON:Self=Self::from_bits(n!(-1)); + pub const ONE:Self=Self::from_bits(n!(1).shl(F as u32)); + pub const TWO:Self=Self::from_bits(n!(2).shl(F as u32)); + pub const HALF:Self=Self::from_bits(n!(1).shl(F as u32-1)); + pub const NEG_ONE:Self=Self::from_bits(n!(-1).shl(F as u32)); + pub const NEG_TWO:Self=Self::from_bits(n!(-2).shl(F as u32)); + pub const NEG_HALF:Self=Self::from_bits(n!(-1).shl(F as u32-1)); } impl Fixed{ #[inline] - pub const fn from_bits(bits:BInt::)->Self{ + pub const fn from_bits(bits:Int::)->Self{ Self{ bits, } } #[inline] - pub const fn to_bits(self)->BInt{ + pub const fn to_bits(self)->Int{ self.bits } #[inline] - pub const fn as_bits(&self)->&BInt{ + pub const fn as_bits(&self)->&Int{ &self.bits } #[inline] - pub const fn as_bits_mut(&mut self)->&mut BInt{ + pub const fn as_bits_mut(&mut self)->&mut Int{ &mut self.bits } #[inline] - pub const fn raw_digit(value:i64)->Self{ - let mut digits=[0u64;N]; - digits[0]=value.abs() as u64; - //sign bit - digits[N-1]|=(value&i64::MIN) as u64; - Self::from_bits(BInt::from_bits(bnum::BUint::from_digits(digits))) + pub const fn from_u64(value:u64)->Self{ + let mut digits=Self::ZERO; + let bytes=value.to_ne_bytes(); + let mut digit=0; + while digitbool{ @@ -99,26 +103,25 @@ impl Fixed{ } } } -impl Fixed<1,F>{ +impl Fixed<{64/BNUM_DIGIT_WIDTH},F>{ /// My old code called this function everywhere so let's provide it #[inline] pub const fn raw(value:i64)->Self{ - Self::from_bits(BInt::from_bits(bnum::BUint::from_digit(value as u64))) + Self::from_bits(Int::from_bytes(value.to_ne_bytes())) } #[inline] pub const fn to_raw(self)->i64{ - let &[digit]=self.to_bits().to_bits().digits(); - digit as i64 + i64::from_le_bytes(self.to_bits().to_bytes()) } } -macro_rules! impl_from { +macro_rules! impl_from{ ($($from:ty),*)=>{ $( impl From<$from> for Fixed{ #[inline] fn from(value:$from)->Self{ - Self::from_bits(BInt::<{N}>::from(value)<>()< std::iter::Sum for Fixed{ } } -const fn signed_shift(lhs:u64,rhs:i32)->u64{ - if rhs.is_negative(){ - lhs>>-rhs - }else{ - lhs< { +macro_rules! impl_into_float{ + ($output:ty,$unsigned:ty,$mantissa_msb:expr,$bias:expr) => { impl Into<$output> for Fixed{ #[inline] fn into(self)->$output{ - const DIGIT_SHIFT:u32=6;//Log2[64] - // SBBB BBBB - // 1001 1110 0000 0000 - let sign=if self.bits.is_negative(){(1 as $unsigned)<<(<$unsigned>::BITS-1)}else{0}; let unsigned=self.bits.unsigned_abs(); - let most_significant_bit=unsigned.bits(); - let exp=if unsigned.is_zero(){ - 0 - }else{ - let msb=most_significant_bit as $unsigned; - let _127=((1 as $unsigned)<<($exponent_bits-1))-1; - let msb_offset=msb+_127-1-F as $unsigned; - msb_offset<<($mantissa_bits-1) + // most_significant_bit is the "index" of the most significant bit. + // 0b0000_0000.msb()==0 (but we just special case return 0.0) + // 0b0000_0001.msb()==0 + // 0b1000_0000.msb()==7 + let Some(most_significant_bit)=unsigned.bit_width().checked_sub(1)else{ + return 0.0; }; - let digits=unsigned.digits(); - let digit_index=most_significant_bit.saturating_sub(1)>>DIGIT_SHIFT; - let digit=digits[digit_index as usize]; - //How many bits does the mantissa take from this digit - let take_bits=most_significant_bit-(digit_index<::BITS-1)}else{0}; + + // exp + let msb=most_significant_bit as $unsigned; + let msb_offset=msb+$bias-F as $unsigned; + let exp=msb_offset<<$mantissa_msb; + + // mant + let digits=unsigned.to_bytes(); + + // Copy digits into mantissa + let mut m_bytes=[0u8;_]; + + let mant_unmasked; + const MOD8:usize=((1<>DIGIT_SHIFT; + let mut i_d=right_shift>>DIGIT_SHIFT; + while i_m::from_le_bytes(m_bytes); + let right_shift=((right_shift+MANT_REM)&MOD8)+NEG_MANT_REM; + mant_unmasked=unsigned>>right_shift; + }else{ + // lsb of mantissa is lower than lsb of fixed point + // [0,0,0,0,0b0100_0000,0,0,0] + // [0,0b0001_0000,0,0,0,0,0,0]<>DIGIT_SHIFT; + let mut i_d=0; + while i_m::from_le_bytes(m_bytes)<<(left_shift&MOD8); } - let mant=unmasked_mant&((1 as $unsigned)<<($mantissa_bits-1))-1; + + let mant=mant_unmasked&(((1 as $unsigned)<<$mantissa_msb)-1); let bits=sign|exp|mant; <$output>::from_bits(bits) } } } } -impl_into_float!(f32,u32,8,24); -impl_into_float!(f64,u64,11,53); +impl_into_float!(f32,u32,23,127); +impl_into_float!(f64,u64,52,1023); #[inline] -fn integer_decode_f32(f: f32) -> (u64, i16, bool) { +fn integer_decode_f32(f: f32) -> (u32, u8, bool) { let bits: u32 = f.to_bits(); let sign: bool = bits & (1<<31) != 0; - let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; + let exponent = (bits >> 23) & 0xff; let mantissa = if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 }; - // Exponent bias + mantissa shift - exponent -= 127 + 23; - (mantissa as u64, exponent, sign) + (mantissa, exponent as u8, sign) } #[inline] -fn integer_decode_f64(f: f64) -> (u64, i16, bool) { +fn integer_decode_f64(f: f64) -> (u64, u16, bool) { let bits: u64 = f.to_bits(); let sign: bool = bits & (1u64<<63) != 0; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; + let exponent = (bits >> 52) & 0x7ff; let mantissa = if exponent == 0 { (bits & 0xfffffffffffff) << 1 } else { (bits & 0xfffffffffffff) | 0x10000000000000 }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) + (mantissa, exponent as u16, sign) } #[derive(Debug,Eq,PartialEq)] pub enum FixedFromFloatError{ @@ -246,13 +318,12 @@ impl core::fmt::Display for FixedFromFloatError{ write!(f,"{self:?}") } } -macro_rules! impl_from_float { - ( $decode:ident, $input: ty, $mantissa_bits:expr ) => { +macro_rules! impl_from_float{ + ($decode:ident,$input:ty,$mantissa_bits:expr,$bias:expr)=>{ impl TryFrom<$input> for Fixed{ type Error=FixedFromFloatError; #[inline] fn try_from(value:$input)->Result{ - const DIGIT_SHIFT:u32=6; match value.classify(){ std::num::FpCategory::Nan=>Err(FixedFromFloatError::Nan), std::num::FpCategory::Infinite=>Err(FixedFromFloatError::Infinite), @@ -261,25 +332,62 @@ macro_rules! impl_from_float { |std::num::FpCategory::Normal =>{ let (m,e,s)=$decode(value); - let mut digits=[0u64;N]; - let most_significant_bit=e as i32+$mantissa_bits as i32+F as i32; - if most_significant_bit<0{ + let mut digits=[0u8;N]; + let msb_biased=e as usize+F+1; + if msb_biased<$bias{ return Err(FixedFromFloatError::Underflow); + }; + if N*BNUM_DIGIT_WIDTH+$bias<=msb_biased{ + return Err(FixedFromFloatError::Overflow); } - let digit_index=most_significant_bit>>DIGIT_SHIFT; - let digit=digits.get_mut(digit_index as usize).ok_or(FixedFromFloatError::Overflow)?; - let take_bits=most_significant_bit-(digit_index<>DIGIT_SHIFT; + let mut i_m; + let mut i_d; + if digit_index<0{ + // lsb of mantissa is lower than lsb of fixed point + // [0,0,0,0]<= bias, i_m is 0, we skip i_d bytes in digits + i_m = (((($bias + $mantissa_bits) - lsb) >> DIGIT_SHIFT) & is_less); + i_d = ((lsb.wrapping_sub($bias + $mantissa_bits) >> DIGIT_SHIFT) & !is_less); + + // Calculate how many bytes to copy safely + let m_bytes_len = m_bytes.len(); + let count = (m_bytes_len.saturating_sub(i_m)).min(N.saturating_sub(i_d)); + + if count > 0 { + digits[i_d..i_d + count].copy_from_slice(&m_bytes[i_m..i_m + count]); + } + */ + + let bits=Int::from_bytes(digits); Ok(if s{ Self::from_bits(bits.overflowing_neg().0) }else{ @@ -291,14 +399,14 @@ macro_rules! impl_from_float { } } } -impl_from_float!(integer_decode_f32,f32,24); -impl_from_float!(integer_decode_f64,f64,53); +impl_from_float!(integer_decode_f32,f32,24,127); +impl_from_float!(integer_decode_f64,f64,53,1023); impl core::fmt::Debug for Fixed{ #[inline] fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{ let integral=self.as_bits().unsigned_abs()>>F; - let fractional=self.as_bits().unsigned_abs()&((bnum::BUint::::ONE<::ONE); + let fractional=self.as_bits().unsigned_abs()&((n!(1)<>2; if self.is_negative(){ core::write!(f,"-")?; @@ -320,14 +428,14 @@ impl core::fmt::Display for Fixed{ } macro_rules! impl_additive_operator { - ( $struct: ident, $trait: ident, $method: ident, $output: ty ) => { - impl $struct{ + ( $trait: ident, $method: ident, $output: ty ) => { + impl Fixed{ #[inline] pub const fn $method(self, other: Self) -> Self { Self::from_bits(self.bits.$method(other.bits)) } } - impl core::ops::$trait for $struct{ + impl core::ops::$trait for Fixed{ type Output = $output; #[inline] fn $method(self, other: Self) -> Self::Output { @@ -337,8 +445,8 @@ macro_rules! impl_additive_operator { }; } macro_rules! impl_additive_assign_operator { - ( $struct: ident, $trait: ident, $method: ident ) => { - impl core::ops::$trait for $struct{ + ( $trait: ident, $method: ident ) => { + impl core::ops::$trait for Fixed{ #[inline] fn $method(&mut self, other: Self) { self.bits.$method(other.bits); @@ -348,28 +456,28 @@ macro_rules! impl_additive_assign_operator { } // Impl arithmetic pperators -impl_additive_assign_operator!( Fixed, AddAssign, add_assign ); -impl_additive_operator!( Fixed, Add, add, Self ); -impl_additive_assign_operator!( Fixed, SubAssign, sub_assign ); -impl_additive_operator!( Fixed, Sub, sub, Self ); -impl_additive_assign_operator!( Fixed, RemAssign, rem_assign ); -impl_additive_operator!( Fixed, Rem, rem, Self ); +impl_additive_assign_operator!( AddAssign, add_assign ); +impl_additive_operator!( Add, add, Self ); +impl_additive_assign_operator!( SubAssign, sub_assign ); +impl_additive_operator!( Sub, sub, Self ); +impl_additive_assign_operator!( RemAssign, rem_assign ); +impl_additive_operator!( Rem, rem, Self ); // Impl bitwise operators -impl_additive_assign_operator!( Fixed, BitAndAssign, bitand_assign ); -impl_additive_operator!( Fixed, BitAnd, bitand, Self ); -impl_additive_assign_operator!( Fixed, BitOrAssign, bitor_assign ); -impl_additive_operator!( Fixed, BitOr, bitor, Self ); -impl_additive_assign_operator!( Fixed, BitXorAssign, bitxor_assign ); -impl_additive_operator!( Fixed, BitXor, bitxor, Self ); +impl_additive_assign_operator!( BitAndAssign, bitand_assign ); +impl_additive_operator!( BitAnd, bitand, Self ); +impl_additive_assign_operator!( BitOrAssign, bitor_assign ); +impl_additive_operator!( BitOr, bitor, Self ); +impl_additive_assign_operator!( BitXorAssign, bitxor_assign ); +impl_additive_operator!( BitXor, bitxor, Self ); // non-wide operators. The result is the same width as the inputs. // This macro is not used in the default configuration. #[expect(unused_macros)] macro_rules! impl_multiplicative_operator_not_const_generic { - ( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => { - impl core::ops::$trait for $struct<$width,F>{ + ( ($trait: ident, $method: ident, $output: ty ), $width:expr ) => { + impl core::ops::$trait for Fixed<{$width/BNUM_DIGIT_WIDTH},F>{ type Output = $output; #[inline] fn $method(self, other: Self) -> Self::Output { @@ -381,8 +489,8 @@ macro_rules! impl_multiplicative_operator_not_const_generic { }; } macro_rules! impl_multiplicative_assign_operator_not_const_generic { - ( ($struct: ident, $trait: ident, $method: ident, $non_assign_method: ident ), $width:expr ) => { - impl core::ops::$trait for $struct<$width,F>{ + ( ($trait: ident, $method: ident, $non_assign_method: ident ), $width:expr ) => { + impl core::ops::$trait for Fixed<{$width/BNUM_DIGIT_WIDTH},F>{ #[inline] fn $method(&mut self, other: Self) { paste::item!{ @@ -394,13 +502,13 @@ macro_rules! impl_multiplicative_assign_operator_not_const_generic { } macro_rules! impl_multiply_operator_not_const_generic { - ( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => { - impl $struct<$width,F>{ + ( ($trait: ident, $method: ident, $output: ty ), $width:expr ) => { + impl Fixed<{$width/BNUM_DIGIT_WIDTH},F>{ paste::item!{ #[inline] pub fn [](self, rhs: Self) -> Self { let (low,high)=self.bits.unsigned_abs().widening_mul(rhs.bits.unsigned_abs()); - let out:BInt::<{$width*2}>=unsafe{core::mem::transmute([low,high])}; + let out:Int::<{$width*2/BNUM_DIGIT_WIDTH}>=unsafe{core::mem::transmute([low,high])}; if self.is_negative()==rhs.is_negative(){ Self::from_bits(out.shr(F as u32).as_()) }else{ @@ -410,34 +518,34 @@ macro_rules! impl_multiply_operator_not_const_generic { } } #[cfg(not(feature="wide-mul"))] - impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width); + impl_multiplicative_operator_not_const_generic!(($trait,$method,$output),$width); #[cfg(feature="deferred-division")] - impl ratio_ops::ratio::Divide for Fixed<$width,{$width*32}>{ + impl ratio_ops::ratio::Divide for Fixed<{$width/BNUM_DIGIT_WIDTH},{$width>>1}>{ type Output=Self; #[inline] fn divide(self, other: i64)->Self::Output{ - Self::from_bits(self.bits.div_euclid(BInt::from(other))) + Self::from_bits(self.bits.div_euclid(other.as_())) } } } } macro_rules! impl_divide_operator_not_const_generic { - ( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => { - impl $struct<$width,F>{ + ( ($trait: ident, $method: ident, $output: ty ), $width:expr ) => { + impl Fixed<{$width/BNUM_DIGIT_WIDTH},F>{ paste::item!{ #[inline] pub fn [](self,other:Self)->Self{ //this only needs to be $width+F as u32/64+1 but MUH CONST GENERICS!!!!! - let lhs=self.bits.as_::>().shl(F as u32); - let rhs=other.bits.as_::>(); + let lhs=self.bits.as_::>().shl(F as u32); + let rhs=other.bits.as_::>(); Self::from_bits(lhs.div_euclid(rhs).as_()) } } } #[cfg(all(not(feature="wide-mul"),not(feature="deferred-division")))] - impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width); + impl_multiplicative_operator_not_const_generic!(($trait,$method,$output),$width); #[cfg(all(not(feature="wide-mul"),feature="deferred-division"))] - impl ratio_ops::ratio::Divide for $struct<$width,F>{ + impl ratio_ops::ratio::Divide for Fixed<{$width/BNUM_DIGIT_WIDTH},F>{ type Output = $output; #[inline] fn divide(self, other: Self) -> Self::Output { @@ -450,28 +558,28 @@ macro_rules! impl_divide_operator_not_const_generic { } macro_rules! impl_multiplicative_operator { - ( $struct: ident, $trait: ident, $method: ident, $inner_method: ident, $output: ty ) => { - impl core::ops::$trait for $struct + ( $trait: ident, $method: ident, $inner_method: ident, $output: ty ) => { + impl core::ops::$trait for Fixed where - BInt:::From+core::ops::$trait, + Int:::bnum::cast::CastFrom+core::ops::$trait, { type Output = $output; #[inline] fn $method(self,other:U)->Self::Output{ - Self::from_bits(self.bits.$inner_method(BInt::::from(other))) + Self::from_bits(self.bits.$inner_method(other.as_())) } } }; } macro_rules! impl_multiplicative_assign_operator { - ( $struct: ident, $trait: ident, $method: ident, $not_assign_method: ident ) => { - impl core::ops::$trait for $struct + ( $trait: ident, $method: ident, $not_assign_method: ident ) => { + impl core::ops::$trait for Fixed where - BInt:::From+core::ops::$trait, + Int:::bnum::cast::CastFrom+core::ops::$trait, { #[inline] fn $method(&mut self,other:U){ - self.bits=self.bits.$not_assign_method(BInt::::from(other)); + self.bits=self.bits.$not_assign_method(other.as_()); } } }; @@ -491,18 +599,18 @@ macro_rules! macro_repeated{ macro_rules! macro_16 { ( $macro: ident, $any:tt ) => { - macro_repeated!($macro,$any,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); + macro_repeated!($macro,$any,64,128,192,256,320,384,448,512,576,640,704,768,832,896,960,1024); } } -macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, MulAssign, mul_assign, mul) ); -macro_16!( impl_multiply_operator_not_const_generic, (Fixed, Mul, mul, Self) ); -macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, DivAssign, div_assign, div_euclid) ); -macro_16!( impl_divide_operator_not_const_generic, (Fixed, Div, div_euclid, Self) ); -impl_multiplicative_assign_operator!( Fixed, MulAssign, mul_assign, mul ); -impl_multiplicative_operator!( Fixed, Mul, mul, mul, Self ); -impl_multiplicative_assign_operator!( Fixed, DivAssign, div_assign, div_euclid ); -impl_multiplicative_operator!( Fixed, Div, div, div_euclid, Self ); +macro_16!( impl_multiplicative_assign_operator_not_const_generic, (MulAssign, mul_assign, mul) ); +macro_16!( impl_multiply_operator_not_const_generic, (Mul, mul, Self) ); +macro_16!( impl_multiplicative_assign_operator_not_const_generic, (DivAssign, div_assign, div_euclid) ); +macro_16!( impl_divide_operator_not_const_generic, (Div, div_euclid, Self) ); +impl_multiplicative_assign_operator!( MulAssign, mul_assign, mul ); +impl_multiplicative_operator!( Mul, mul, mul, Self ); +impl_multiplicative_assign_operator!( DivAssign, div_assign, div_euclid ); +impl_multiplicative_operator!( Div, div, div_euclid, Self ); #[cfg(feature="deferred-division")] impl core::ops::Div> for Fixed{ type Output=ratio_ops::ratio::Ratio,Fixed>; @@ -518,8 +626,8 @@ impl ratio_ops::ratio::Parity for Fixed{ } } macro_rules! impl_shift_operator { - ( $struct: ident, $trait: ident, $method: ident, $output: ty ) => { - impl core::ops::$trait for $struct{ + ( $trait: ident, $method: ident, $output: ty ) => { + impl core::ops::$trait for Fixed{ type Output = $output; #[inline] fn $method(self, other: u32) -> Self::Output { @@ -529,8 +637,8 @@ macro_rules! impl_shift_operator { }; } macro_rules! impl_shift_assign_operator { - ( $struct: ident, $trait: ident, $method: ident ) => { - impl core::ops::$trait for $struct{ + ( $trait: ident, $method: ident ) => { + impl core::ops::$trait for Fixed{ #[inline] fn $method(&mut self, other: u32) { self.bits.$method(other); @@ -538,40 +646,40 @@ macro_rules! impl_shift_assign_operator { } }; } -impl_shift_assign_operator!( Fixed, ShlAssign, shl_assign ); -impl_shift_operator!( Fixed, Shl, shl, Self ); -impl_shift_assign_operator!( Fixed, ShrAssign, shr_assign ); -impl_shift_operator!( Fixed, Shr, shr, Self ); +impl_shift_assign_operator!( ShlAssign, shl_assign ); +impl_shift_operator!( Shl, shl, Self ); +impl_shift_assign_operator!( ShrAssign, shr_assign ); +impl_shift_operator!( Shr, shr, Self ); // wide operators. The result width is the sum of the input widths, i.e. none of the multiplication #[allow(unused_macros)] macro_rules! impl_wide_operators{ ($lhs:expr,$rhs:expr)=>{ - impl core::ops::Mul> for Fixed<$lhs,{$lhs*32}>{ - type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>; + impl core::ops::Mul>1}>> for Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}>{ + type Output=Fixed<{($lhs+$rhs)/BNUM_DIGIT_WIDTH},{($lhs+$rhs)>>1}>; #[inline] - fn mul(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{ + fn mul(self, other: Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>)->Self::Output{ paste::item!{ self.[](other) } } } #[cfg(not(feature="deferred-division"))] - impl core::ops::Div> for Fixed<$lhs,{$lhs*32}>{ - type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>; + impl core::ops::Div>1}>> for Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}>{ + type Output=Fixed<{($lhs+$rhs)/BNUM_DIGIT_WIDTH},{($lhs+$rhs)>>1}>; #[inline] - fn div(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{ + fn div(self, other: Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>)->Self::Output{ paste::item!{ self.[](other) } } } #[cfg(feature="deferred-division")] - impl ratio_ops::ratio::Divide> for Fixed<$lhs,{$lhs*32}>{ - type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>; + impl ratio_ops::ratio::Divide>1}>> for Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}>{ + type Output=Fixed<{($lhs+$rhs)/BNUM_DIGIT_WIDTH},{($lhs+$rhs)>>1}>; #[inline] - fn divide(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{ + fn divide(self, other: Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>)->Self::Output{ paste::item!{ self.[](other) } @@ -588,23 +696,23 @@ macro_rules! impl_wide_not_const_generic{ (), ($lhs:expr,$rhs:expr) )=>{ - impl Fixed<$lhs,{$lhs*32}> + impl Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}> { paste::item!{ #[inline] - pub fn [](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{ - let lhs=self.bits.as_::>(); - let rhs=rhs.bits.as_::>(); + pub fn [](self,rhs:Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>)->Fixed<{($lhs+$rhs)/BNUM_DIGIT_WIDTH},{($lhs+$rhs)>>1}>{ + let lhs=self.bits.as_::>(); + let rhs=rhs.bits.as_::>(); Fixed::from_bits(lhs*rhs) } /// This operation cannot represent the fraction exactly, /// but it shapes the output to have precision for the /// largest and smallest possible fractions. #[inline] - pub fn [](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{ + pub fn [](self,rhs:Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>)->Fixed<{($lhs+$rhs)/BNUM_DIGIT_WIDTH},{($lhs+$rhs)>>1}>{ // (lhs/2^LHS_FRAC)/(rhs/2^RHS_FRAC) - let lhs=self.bits.as_::>().shl($rhs*64); - let rhs=rhs.bits.as_::>(); + let lhs=self.bits.as_::>().shl($rhs); + let rhs=rhs.bits.as_::>(); Fixed::from_bits(lhs.div_euclid(rhs)) } } @@ -618,13 +726,13 @@ macro_rules! impl_wide_same_size_not_const_generic{ (), $width:expr )=>{ - impl Fixed<$width,{$width*32}> + impl Fixed<{$width/BNUM_DIGIT_WIDTH},{$width>>1}> { paste::item!{ #[inline] - pub fn [](self,rhs:Fixed<$width,{$width*32}>)->Fixed<{$width*2},{$width*2*32}>{ + pub fn [](self,rhs:Fixed<{$width/BNUM_DIGIT_WIDTH},{$width>>1}>)->Fixed<{$width*2/BNUM_DIGIT_WIDTH},{$width*2>>1}>{ let (low,high)=self.bits.unsigned_abs().widening_mul(rhs.bits.unsigned_abs()); - let out:BInt::<{$width*2}>=unsafe{core::mem::transmute([low,high])}; + let out:Int::<{$width*2/BNUM_DIGIT_WIDTH}>=unsafe{core::mem::transmute([low,high])}; if self.is_negative()==rhs.is_negative(){ Fixed::from_bits(out) }else{ @@ -637,10 +745,10 @@ macro_rules! impl_wide_same_size_not_const_generic{ /// but it shapes the output to have precision for the /// largest and smallest possible fractions. #[inline] - pub fn [](self,rhs:Fixed<$width,{$width*32}>)->Fixed<{$width*2},{$width*2*32}>{ + pub fn [](self,rhs:Fixed<{$width/BNUM_DIGIT_WIDTH},{$width>>1}>)->Fixed<{$width*2/BNUM_DIGIT_WIDTH},{$width*2>>1}>{ // (lhs/2^LHS_FRAC)/(rhs/2^RHS_FRAC) - let lhs=self.bits.as_::>().shl($width*64); - let rhs=rhs.bits.as_::>(); + let lhs=self.bits.as_::>().shl($width); + let rhs=rhs.bits.as_::>(); Fixed::from_bits(lhs.div_euclid(rhs)) } } @@ -653,25 +761,25 @@ macro_rules! impl_wide_same_size_not_const_generic{ //const generics sidestepped wahoo macro_repeated!( impl_wide_not_const_generic,(), - (2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1), - (1,2), (3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2), - (1,3),(2,3), (4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3), - (1,4),(2,4),(3,4), (5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4), - (1,5),(2,5),(3,5),(4,5), (6,5),(7,5),(8,5),(9,5),(10,5),(11,5), - (1,6),(2,6),(3,6),(4,6),(5,6), (7,6),(8,6),(9,6),(10,6), - (1,7),(2,7),(3,7),(4,7),(5,7),(6,7), (8,7),(9,7), - (1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8), (9,8), - (1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9), - (1,10),(2,10),(3,10),(4,10),(5,10),(6,10), - (1,11),(2,11),(3,11),(4,11),(5,11), - (1,12),(2,12),(3,12),(4,12), - (1,13),(2,13),(3,13), - (1,14),(2,14), - (1,15) + (128,64),(192,64),(256,64),(320,64),(384,64),(448,64),(512,64),(576,64),(640,64),(704,64),(768,64),(832,64),(896,64),(960,64), + (64,128), (192,128),(256,128),(320,128),(384,128),(448,128),(512,128),(576,128),(640,128),(704,128),(768,128),(832,128),(896,128), + (64,192),(128,192), (256,192),(320,192),(384,192),(448,192),(512,192),(576,192),(640,192),(704,192),(768,192),(832,192), + (64,256),(128,256),(192,256), (320,256),(384,256),(448,256),(512,256),(576,256),(640,256),(704,256),(768,256), + (64,320),(128,320),(192,320),(256,320), (384,320),(448,320),(512,320),(576,320),(640,320),(704,320), + (64,384),(128,384),(192,384),(256,384),(320,384), (448,384),(512,384),(576,384),(640,384), + (64,448),(128,448),(192,448),(256,448),(320,448),(384,448), (512,448),(576,448), + (64,512),(128,512),(192,512),(256,512),(320,512),(384,512),(448,512), (576,512), + (64,576),(128,576),(192,576),(256,576),(320,576),(384,576),(448,576), + (64,640),(128,640),(192,640),(256,640),(320,640),(384,640), + (64,704),(128,704),(192,704),(256,704),(320,704), + (64,768),(128,768),(192,768),(256,768), + (64,832),(128,832),(192,832), + (64,896),(128,896), + (64,960) ); macro_repeated!( impl_wide_same_size_not_const_generic,(), - 1,2,3,4,5,6,7,8 + 64,128,192,256,320,384,448,512 ); #[derive(Debug,Eq,PartialEq)] @@ -702,43 +810,43 @@ macro_rules! impl_narrow_not_const_generic{ ($lhs:expr,$rhs:expr) )=>{ paste::item!{ - impl Fixed<$lhs,{$lhs*32}> + impl Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}> { #[inline] - pub fn [](self)->Fixed<$rhs,{$rhs*32}>{ - Fixed::from_bits(bnum::cast::As::as_::>(self.bits.shr(($lhs-$rhs)*32))) + pub fn [](self)->Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>{ + Fixed::from_bits(bnum::cast::As::as_::>(self.bits.shr(($lhs-$rhs)>>1))) } #[inline] - pub fn [](self)->Result,NarrowError>{ - if Fixed::<$rhs,{$rhs*32}>::MAX.[]().bits](self)->Result>1}>,NarrowError>{ + if Fixed::<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>::MAX.[]().bits::MIN.[]().bits{ + if self.bits>1}>::MIN.[]().bits{ return Err(NarrowError::Underflow); } Ok(self.[]()) } #[inline] - pub fn [](self)->Fixed<$rhs,{$rhs*32}>{ + pub fn [](self)->Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>{ self.[]().clamp() } } - impl Wrap> for Fixed<$lhs,{$lhs*32}>{ + impl Wrap>1}>> for Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}>{ #[inline] - fn wrap(self)->Fixed<$rhs,{$rhs*32}>{ + fn wrap(self)->Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>{ self.[]() } } - impl TryInto> for Fixed<$lhs,{$lhs*32}>{ + impl TryInto>1}>> for Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}>{ type Error=NarrowError; #[inline] - fn try_into(self)->Result,Self::Error>{ + fn try_into(self)->Result>1}>,Self::Error>{ self.[]() } } - impl Clamp> for Fixed<$lhs,{$lhs*32}>{ + impl Clamp>1}>> for Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}>{ #[inline] - fn clamp(self)->Fixed<$rhs,{$rhs*32}>{ + fn clamp(self)->Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>{ self.[]() } } @@ -751,16 +859,16 @@ macro_rules! impl_widen_not_const_generic{ ($lhs:expr,$rhs:expr) )=>{ paste::item!{ - impl Fixed<$lhs,{$lhs*32}> + impl Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}> { #[inline] - pub fn [](self)->Fixed<$rhs,{$rhs*32}>{ - Fixed::from_bits(bnum::cast::As::as_::>(self.bits).shl(($rhs-$lhs)*32)) + pub fn [](self)->Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>{ + Fixed::from_bits(bnum::cast::As::as_::>(self.bits).shl(($rhs-$lhs)>>1)) } } - impl Into> for Fixed<$lhs,{$lhs*32}>{ + impl Into>1}>> for Fixed<{$lhs/BNUM_DIGIT_WIDTH},{$lhs>>1}>{ #[inline] - fn into(self)->Fixed<$rhs,{$rhs*32}>{ + fn into(self)->Fixed<{$rhs/BNUM_DIGIT_WIDTH},{$rhs>>1}>{ self.[]() } } @@ -772,45 +880,45 @@ macro_rules! impl_widen_not_const_generic{ macro_repeated!( impl_narrow_not_const_generic,(), - (2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1),(17,1), - (3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2), - (4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3), - (5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),(13,4),(14,4),(15,4),(16,4), - (6,5),(7,5),(8,5),(9,5),(10,5),(11,5),(12,5),(13,5),(14,5),(15,5),(16,5), - (7,6),(8,6),(9,6),(10,6),(11,6),(12,6),(13,6),(14,6),(15,6),(16,6), - (8,7),(9,7),(10,7),(11,7),(12,7),(13,7),(14,7),(15,7),(16,7), - (9,8),(10,8),(11,8),(12,8),(13,8),(14,8),(15,8),(16,8), - (10,9),(11,9),(12,9),(13,9),(14,9),(15,9),(16,9), - (11,10),(12,10),(13,10),(14,10),(15,10),(16,10), - (12,11),(13,11),(14,11),(15,11),(16,11), - (13,12),(14,12),(15,12),(16,12), - (14,13),(15,13),(16,13), - (15,14),(16,14), - (16,15) + (128,64),(192,64),(256,64),(320,64),(384,64),(448,64),(512,64),(576,64),(640,64),(704,64),(768,64),(832,64),(896,64),(960,64),(1024,64),(1088,64), + (192,128),(256,128),(320,128),(384,128),(448,128),(512,128),(576,128),(640,128),(704,128),(768,128),(832,128),(896,128),(960,128),(1024,128), + (256,192),(320,192),(384,192),(448,192),(512,192),(576,192),(640,192),(704,192),(768,192),(832,192),(896,192),(960,192),(1024,192), + (320,256),(384,256),(448,256),(512,256),(576,256),(640,256),(704,256),(768,256),(832,256),(896,256),(960,256),(1024,256), + (384,320),(448,320),(512,320),(576,320),(640,320),(704,320),(768,320),(832,320),(896,320),(960,320),(1024,320), + (448,384),(512,384),(576,384),(640,384),(704,384),(768,384),(832,384),(896,384),(960,384),(1024,384), + (512,448),(576,448),(640,448),(704,448),(768,448),(832,448),(896,448),(960,448),(1024,448), + (576,512),(640,512),(704,512),(768,512),(832,512),(896,512),(960,512),(1024,512), + (640,576),(704,576),(768,576),(832,576),(896,576),(960,576),(1024,576), + (704,640),(768,640),(832,640),(896,640),(960,640),(1024,640), + (768,704),(832,704),(896,704),(960,704),(1024,704), + (832,768),(896,768),(960,768),(1024,768), + (896,832),(960,832),(1024,832), + (960,896),(1024,896), + (1024,960) ); macro_repeated!( impl_widen_not_const_generic,(), - (1,2), - (1,3),(2,3), - (1,4),(2,4),(3,4), - (1,5),(2,5),(3,5),(4,5), - (1,6),(2,6),(3,6),(4,6),(5,6), - (1,7),(2,7),(3,7),(4,7),(5,7),(6,7), - (1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8), - (1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),(8,9), - (1,10),(2,10),(3,10),(4,10),(5,10),(6,10),(7,10),(8,10),(9,10), - (1,11),(2,11),(3,11),(4,11),(5,11),(6,11),(7,11),(8,11),(9,11),(10,11), - (1,12),(2,12),(3,12),(4,12),(5,12),(6,12),(7,12),(8,12),(9,12),(10,12),(11,12), - (1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13), - (1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14), - (1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15), - (1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16), - (1,17) + (64,128), + (64,192),(128,192), + (64,256),(128,256),(192,256), + (64,320),(128,320),(192,320),(256,320), + (64,384),(128,384),(192,384),(256,384),(320,384), + (64,448),(128,448),(192,448),(256,448),(320,448),(384,448), + (64,512),(128,512),(192,512),(256,512),(320,512),(384,512),(448,512), + (64,576),(128,576),(192,576),(256,576),(320,576),(384,576),(448,576),(512,576), + (64,640),(128,640),(192,640),(256,640),(320,640),(384,640),(448,640),(512,640),(576,640), + (64,704),(128,704),(192,704),(256,704),(320,704),(384,704),(448,704),(512,704),(576,704),(640,704), + (64,768),(128,768),(192,768),(256,768),(320,768),(384,768),(448,768),(512,768),(576,768),(640,768),(704,768), + (64,832),(128,832),(192,832),(256,832),(320,832),(384,832),(448,832),(512,832),(576,832),(640,832),(704,832),(768,832), + (64,896),(128,896),(192,896),(256,896),(320,896),(384,896),(448,896),(512,896),(576,896),(640,896),(704,896),(768,896),(832,896), + (64,960),(128,960),(192,960),(256,960),(320,960),(384,960),(448,960),(512,960),(576,960),(640,960),(704,960),(768,960),(832,960),(896,960), + (64,1024),(128,1024),(192,1024),(256,1024),(320,1024),(384,1024),(448,1024),(512,1024),(576,1024),(640,1024),(704,1024),(768,1024),(832,1024),(896,1024),(960,1024), + (64,1088) ); macro_rules! impl_not_const_generic{ ($n:expr,$_2n:expr)=>{ - impl Fixed<$n,{$n*32}>{ + impl Fixed<{$n/BNUM_DIGIT_WIDTH},{$n>>1}>{ paste::item!{ #[inline] pub fn sqrt_unchecked(self)->Self{ @@ -820,18 +928,18 @@ macro_rules! impl_not_const_generic{ //2. divide by 2 via >>1 (sqrt-ish) //3. add on fractional offset //Voila - let used_bits=self.bits.bits() as i32-1-($n*32) as i32; - let max_shift=((used_bits>>1)+($n*32) as i32) as u32; + let used_bits=self.bits.unsigned_abs().bit_width() as i32-1-($n>>1) as i32; + let max_shift=((used_bits>>1)+($n>>1) as i32) as u32; let mut result=Self::ZERO; //resize self to match the wide mul output let wide_self=self.[](); //descend down the bits and check if flipping each bit would push the square over the input value for shift in (0..=max_shift).rev(){ - result.as_bits_mut().as_bits_mut().set_bit(shift,true); + result.as_bits_mut().set_bit(shift,true); if wide_self](result){ // put it back lol - result.as_bits_mut().as_bits_mut().set_bit(shift,false); + result.as_bits_mut().set_bit(shift,false); } } result @@ -856,11 +964,11 @@ macro_rules! impl_not_const_generic{ } } } -impl_not_const_generic!(1,2); -impl_not_const_generic!(2,4); -impl_not_const_generic!(3,6); -impl_not_const_generic!(4,8); -impl_not_const_generic!(5,10); -impl_not_const_generic!(6,12); -impl_not_const_generic!(7,14); -impl_not_const_generic!(8,16); +impl_not_const_generic!(64,128); +impl_not_const_generic!(128,256); +impl_not_const_generic!(192,384); +impl_not_const_generic!(256,512); +impl_not_const_generic!(320,640); +impl_not_const_generic!(384,768); +impl_not_const_generic!(448,896); +impl_not_const_generic!(512,1024); diff --git a/lib/fixed_wide/src/tests.rs b/lib/fixed_wide/src/tests.rs index 0b3be4d2..c729f41c 100644 --- a/lib/fixed_wide/src/tests.rs +++ b/lib/fixed_wide/src/tests.rs @@ -1,208 +1,273 @@ -use crate::types::I32F32; -use crate::types::I256F256; +use crate::fixed::Fixed; +use crate::types::{F64_32,F128_64,F192_96,F512_256}; #[test] fn you_can_add_numbers(){ - let a=I256F256::from((3i128*2).pow(4)); - assert_eq!(a+a,I256F256::from((3i128*2).pow(4)*2)); + let a=F512_256::from((3i128*2).pow(4)); + assert_eq!(a+a,F512_256::from((3i128*2).pow(4)*2)); +} + +macro_rules! test_bit_by_bit{ + ($n:expr,$float:ty,$mantissa_bits:expr)=>{{ + const MANT:u64=(1<<$mantissa_bits)-1; + // all bits in range + for i in 0..$n-$mantissa_bits{ + let a=Fixed::<{$n/8},{$n>>1}>::from_bits(bnum::cast::As::as_::>(MANT).shl(i)); + let b=(MANT as $float)*(2.0 as $float).powi(i as i32-{$n>>1}); + let f:$float=a.into(); + assert_eq!(f,b,"F{}_{} Into float {i}",$n,$n>>1); + assert_eq!(a,b.try_into().unwrap(),"F{}_{} From float {i}",$n,$n>>1); + } + // underflow + for i in 0u32..$mantissa_bits{ + let a=Fixed::<{$n/8},{$n>>1}>::from_bits(bnum::cast::As::as_::>(MANT>>i)); + let b=((MANT>>i) as $float)*(2.0 as $float).powi(-{$n>>1}); + let f:$float=a.into(); + assert_eq!(f,b,"Underflow F{}_{} Into float {i}",$n,$n>>1); + assert_eq!(a,b.try_into().unwrap(),"Underflow F{}_{} From float {i}",$n,$n>>1); + } + }}; +} + +#[test] +fn test_many(){ + test_bit_by_bit!(64,f32,24); + test_bit_by_bit!(128,f32,24); + // f32 is reaching its limits here + // test_bit_by_bit!(256,f32,24); + // test_bit_by_bit!(512,f32,24); + test_bit_by_bit!(64,f64,53); + test_bit_by_bit!(128,f64,53); + test_bit_by_bit!(256,f64,53); + test_bit_by_bit!(512,f64,53); } #[test] fn to_f32(){ - let a=I256F256::from(1)>>2; + let a=F64_32::ZERO; + let f:f32=a.into(); + assert_eq!(f,0.0f32); + let a=F64_32::from(1)>>2; let f:f32=a.into(); assert_eq!(f,0.25f32); let f:f32=(-a).into(); assert_eq!(f,-0.25f32); - let a=I256F256::from(0); + let a=F64_32::MIN; + let f:f32=a.into(); + assert_eq!(f,i32::MIN as f32); + let a=F512_256::from(1)>>2; + let f:f32=a.into(); + assert_eq!(f,0.25f32); + let f:f32=(-a).into(); + assert_eq!(f,-0.25f32); + let a=F512_256::from(0); let f:f32=(-a).into(); assert_eq!(f,0f32); - let a=I256F256::from(237946589723468975i64)<<16; + let a=F512_256::from(237946589723468975i64)<<16; let f:f32=a.into(); assert_eq!(f,237946589723468975f32*2.0f32.powi(16)); } #[test] fn to_f64(){ - let a=I256F256::from(1)>>2; + let a=F64_32::ZERO; + let f:f64=a.into(); + assert_eq!(f,0.0f64); + let a=F64_32::from(1)>>2; let f:f64=a.into(); assert_eq!(f,0.25f64); let f:f64=(-a).into(); assert_eq!(f,-0.25f64); - let a=I256F256::from(0); + let a=F64_32::MIN; + let f:f64=a.into(); + assert_eq!(f,i32::MIN as f64); + let a=F512_256::from(1)>>2; + let f:f64=a.into(); + assert_eq!(f,0.25f64); + let f:f64=(-a).into(); + assert_eq!(f,-0.25f64); + let a=F512_256::from(0); let f:f64=(-a).into(); assert_eq!(f,0f64); - let a=I256F256::from(237946589723468975i64)<<16; + let a=F512_256::from(237946589723468975i64)<<16; let f:f64=a.into(); assert_eq!(f,237946589723468975f64*2.0f64.powi(16)); } #[test] fn from_f32(){ - let a=I256F256::from(1)>>2; - let b:Result=0.25f32.try_into(); + let a=F64_32::ZERO; + let b:Result=0.0f32.try_into(); assert_eq!(b,Ok(a)); - let a=I256F256::from(-1)>>2; - let b:Result=(-0.25f32).try_into(); + let a=F512_256::from(1)>>2; + let b:Result=0.25f32.try_into(); assert_eq!(b,Ok(a)); - let a=I256F256::from(0); - let b:Result=0.try_into(); + let a=F512_256::from(-1)>>2; + let b:Result=(-0.25f32).try_into(); assert_eq!(b,Ok(a)); - let a=I256F256::from(0b101011110101001010101010000000000000000000000000000i64)<<16; - let b:Result=(0b101011110101001010101010000000000000000000000000000u64 as f32*2.0f32.powi(16)).try_into(); + let a=F512_256::from(0); + let b:Result=0.try_into(); + assert_eq!(b,Ok(a)); + let a=F512_256::from(0b101011110101001010101010000000000000000000000000000i64)<<16; + let b:Result=(0b101011110101001010101010000000000000000000000000000u64 as f32*2.0f32.powi(16)).try_into(); assert_eq!(b,Ok(a)); //I32F32::MAX into f32 is truncated into this value - let a=I32F32::raw(0b111111111111111111111111000000000000000000000000000000000000000i64); - let b:Result=Into::::into(I32F32::MAX).try_into(); + let a=F64_32::raw(0b111111111111111111111111000000000000000000000000000000000000000i64); + let b:Result=Into::::into(F64_32::MAX).try_into(); assert_eq!(b,Ok(a)); //I32F32::MIN hits a special case since it's not representable as a positive signed integer //TODO: don't return an overflow because this is technically possible - let _a=I32F32::MIN; - let b:Result=Into::::into(I32F32::MIN).try_into(); + let a=F64_32::MIN; + let f:f32=a.into(); + let b:Result=f.try_into(); assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow)); //16 is within the 24 bits of float precision - let b:Result=Into::::into(-I32F32::MIN.widen_2()).try_into(); + let a=-F64_32::MIN.widen_128(); + let f:f32=a.into(); + let b:Result=f.try_into(); assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow)); - let b:Result=f32::MIN_POSITIVE.try_into(); + let b:Result=f32::MIN_POSITIVE.try_into(); assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Underflow)); //test many cases for i in 0..64{ - let a=crate::fixed::Fixed::<2,64>::raw_digit(0b111111111111111111111111000000000000000000000000000000000000000i64)<,_>=f.try_into(); + let b:Result=f.try_into(); assert_eq!(b,Ok(a)); } } #[test] fn from_f64(){ - let a=I256F256::from(1)>>2; - let b:Result=0.25f64.try_into(); + let a=F64_32::ZERO; + let b:Result=0.0f64.try_into(); assert_eq!(b,Ok(a)); - let a=I256F256::from(-1)>>2; - let b:Result=(-0.25f64).try_into(); + let a=F512_256::from(1)>>2; + let b:Result=0.25f64.try_into(); assert_eq!(b,Ok(a)); - let a=I256F256::from(0); - let b:Result=0.try_into(); + let a=F512_256::from(-1)>>2; + let b:Result=(-0.25f64).try_into(); assert_eq!(b,Ok(a)); - let a=I256F256::from(0b101011110101001010101010000000000000000000000000000i64)<<16; - let b:Result=(0b101011110101001010101010000000000000000000000000000u64 as f64*2.0f64.powi(16)).try_into(); + let a=F512_256::from(0); + let b:Result=0.try_into(); + assert_eq!(b,Ok(a)); + let a=F512_256::from(0b101011110101001010101010000000000000000000000000000i64)<<16; + let b:Result=(0b101011110101001010101010000000000000000000000000000u64 as f64*2.0f64.powi(16)).try_into(); assert_eq!(b,Ok(a)); } #[test] fn you_can_shr_numbers(){ - let a=I32F32::from(4); - assert_eq!(a>>1,I32F32::from(2)); + let a=F64_32::from(4); + assert_eq!(a>>1,F64_32::from(2)); } #[test] fn test_wide_mul(){ - let a=I32F32::ONE; - let aa=a.wide_mul_1_1(a); - assert_eq!(aa,crate::types::I64F64::ONE); + let a=F64_32::ONE; + let aa=a.wide_mul_64_64(a); + assert_eq!(aa,F128_64::ONE); } #[test] fn test_wide_div(){ - let a=I32F32::ONE*4; - let b=I32F32::ONE*2; - let wide_a=a.wide_mul_1_1(I32F32::ONE); - let wide_b=b.wide_mul_1_1(I32F32::ONE); - let ab=a.wide_div_1_1(b); - assert_eq!(ab,crate::types::I64F64::ONE*2); - let wab=wide_a.wide_div_2_1(b); - assert_eq!(wab,crate::fixed::Fixed::<3,96>::ONE*2); - let awb=a.wide_div_1_2(wide_b); - assert_eq!(awb,crate::fixed::Fixed::<3,96>::ONE*2); + let a=F64_32::ONE*4; + let b=F64_32::ONE*2; + let wide_a=a.wide_mul_64_64(F64_32::ONE); + let wide_b=b.wide_mul_64_64(F64_32::ONE); + let ab=a.wide_div_64_64(b); + assert_eq!(ab,F128_64::ONE*2); + let wab=wide_a.wide_div_128_64(b); + assert_eq!(wab,F192_96::ONE*2); + let awb=a.wide_div_64_128(wide_b); + assert_eq!(awb,F192_96::ONE*2); } #[test] fn test_wide_mul_repeated() { - let a=I32F32::from(2); - let b=I32F32::from(3); + let a=F64_32::from(2); + let b=F64_32::from(3); - let w1=a.wide_mul_1_1(b); - let w2=w1.wide_mul_2_2(w1); - let w3=w2.wide_mul_4_4(w2); + let w1=a.wide_mul_64_64(b); + let w2=w1.wide_mul_128_128(w1); + let w3=w2.wide_mul_256_256(w2); - assert_eq!(w3,I256F256::from((3i128*2).pow(4))); + assert_eq!(w3,F512_256::from((3i128*2).pow(4))); } #[test] fn test_bint(){ - let a=I32F32::ONE; - assert_eq!(a*2,I32F32::from(2)); + let a=F64_32::ONE; + assert_eq!(a*2,F64_32::from(2)); } #[test] fn test_wrap(){ - assert_eq!(I32F32::ONE,I256F256::ONE.wrap_1()); - assert_eq!(I32F32::NEG_ONE,I256F256::NEG_ONE.wrap_1()); + assert_eq!(F64_32::ONE,F512_256::ONE.wrap_64()); + assert_eq!(F64_32::NEG_ONE,F512_256::NEG_ONE.wrap_64()); } #[test] fn test_narrow(){ - assert_eq!(Ok(I32F32::ONE),I256F256::ONE.narrow_1()); - assert_eq!(Ok(I32F32::NEG_ONE),I256F256::NEG_ONE.narrow_1()); + assert_eq!(Ok(F64_32::ONE),F512_256::ONE.narrow_64()); + assert_eq!(Ok(F64_32::NEG_ONE),F512_256::NEG_ONE.narrow_64()); } #[test] fn test_widen(){ - assert_eq!(I32F32::ONE.widen_8(),I256F256::ONE); - assert_eq!(I32F32::NEG_ONE.widen_8(),I256F256::NEG_ONE); + assert_eq!(F64_32::ONE.widen_512(),F512_256::ONE); + assert_eq!(F64_32::NEG_ONE.widen_512(),F512_256::NEG_ONE); } #[test] fn test_clamp(){ - assert_eq!(I32F32::ONE,I256F256::ONE.clamp_1()); - assert_eq!(I32F32::NEG_ONE,I256F256::NEG_ONE.clamp_1()); + assert_eq!(F64_32::ONE,F512_256::ONE.clamp_64()); + assert_eq!(F64_32::NEG_ONE,F512_256::NEG_ONE.clamp_64()); } #[test] fn test_sqrt(){ - let a=I32F32::ONE*4; - assert_eq!(a.sqrt(),I32F32::from(2)); + let a=F64_32::ONE*4; + assert_eq!(a.sqrt(),F64_32::from(2)); } #[test] fn test_sqrt_zero(){ - let a=I32F32::ZERO; - assert_eq!(a.sqrt(),I32F32::ZERO); + let a=F64_32::ZERO; + assert_eq!(a.sqrt(),F64_32::ZERO); } #[test] fn test_sqrt_low(){ - let a=I32F32::HALF; + let a=F64_32::HALF; let b=a.fixed_mul(a); assert_eq!(b.sqrt(),a); } -fn find_equiv_sqrt_via_f64(n:I32F32)->I32F32{ +fn find_equiv_sqrt_via_f64(n:F64_32)->F64_32{ //GIMME THEM BITS BOY - let &[bits]=n.to_bits().to_bits().digits(); - let ibits=bits as i64; + let ibits=i64::from_le_bytes(n.to_bits().to_bytes()); let f=(ibits as f64)/((1u64<<32) as f64); let f_ans=f.sqrt(); - let i=(f_ans*((1u64<<32) as f64)) as i64; - let r=I32F32::from_bits(bnum::BInt::<1>::from(i)); + let i=(f_ans*((1u64<<32) as f64)) as u64; + let r=F64_32::from_u64(i); //mimic the behaviour of the algorithm, //return the result if it truncates to the exact answer - if (r+I32F32::EPSILON).wide_mul_1_1(r+I32F32::EPSILON)==n.wide_mul_1_1(I32F32::ONE){ - return r+I32F32::EPSILON; + if (r+F64_32::EPSILON).wide_mul_64_64(r+F64_32::EPSILON)==n.wide_mul_64_64(F64_32::ONE){ + return r+F64_32::EPSILON; } - if (r-I32F32::EPSILON).wide_mul_1_1(r-I32F32::EPSILON)==n.wide_mul_1_1(I32F32::ONE){ - return r-I32F32::EPSILON; + if (r-F64_32::EPSILON).wide_mul_64_64(r-F64_32::EPSILON)==n.wide_mul_64_64(F64_32::ONE){ + return r-F64_32::EPSILON; } return r; } -fn test_exact(n:I32F32){ +fn test_exact(n:F64_32){ assert_eq!(n.sqrt(),find_equiv_sqrt_via_f64(n)); } #[test] fn test_sqrt_exact(){ //43 for i in 0..((i64::MAX as f32).ln() as u32){ - let n=I32F32::from_bits(bnum::BInt::<1>::from((i as f32).exp() as i64)); + let n=F64_32::from_u64((i as f32).exp() as u64); test_exact(n); } } #[test] fn test_sqrt_max(){ - let a=I32F32::MAX; + let a=F64_32::MAX; test_exact(a); } #[test] @@ -210,9 +275,9 @@ fn test_sqrt_max(){ fn test_zeroes_normal(){ // (x-1)*(x+1) // x^2-1 - let zeroes=I32F32::zeroes2(I32F32::NEG_ONE,I32F32::ZERO,I32F32::ONE); + let zeroes=F64_32::zeroes2(F64_32::NEG_ONE,F64_32::ZERO,F64_32::ONE); assert_eq!(zeroes,arrayvec::ArrayVec::from_iter([I32F32::NEG_ONE,I32F32::ONE])); - let zeroes=I32F32::zeroes2(I32F32::NEG_ONE*3,I32F32::ONE*2,I32F32::ONE); + let zeroes=F64_32::zeroes2(F64_32::NEG_ONE*3,F64_32::ONE*2,F64_32::ONE); assert_eq!(zeroes,arrayvec::ArrayVec::from_iter([I32F32::NEG_ONE*3,I32F32::ONE])); } #[test] @@ -220,25 +285,25 @@ fn test_zeroes_normal(){ fn test_zeroes_deferred_division(){ // (x-1)*(x+1) // x^2-1 - let zeroes=I32F32::zeroes2(I32F32::NEG_ONE,I32F32::ZERO,I32F32::ONE); + let zeroes=F64_32::zeroes2(F64_32::NEG_ONE,F64_32::ZERO,F64_32::ONE); assert_eq!( zeroes, arrayvec::ArrayVec::from_iter([ - ratio_ops::ratio::Ratio::new(I32F32::ONE*2,I32F32::NEG_ONE*2), - ratio_ops::ratio::Ratio::new(I32F32::ONE*2,I32F32::ONE*2), + ratio_ops::ratio::Ratio::new(F64_32::ONE*2,F64_32::NEG_ONE*2), + ratio_ops::ratio::Ratio::new(F64_32::ONE*2,F64_32::ONE*2), ]) ); } #[test] fn test_debug(){ - assert_eq!(format!("{:?}",I32F32::EPSILON),"0.00000001"); - assert_eq!(format!("{:?}",I32F32::ONE),"1.00000000"); - assert_eq!(format!("{:?}",I32F32::TWO),"2.00000000"); - assert_eq!(format!("{:?}",I32F32::MAX),"7fffffff.ffffffff"); - assert_eq!(format!("{:?}",I32F32::try_from(core::f64::consts::PI).unwrap()),"3.243f6a88"); - assert_eq!(format!("{:?}",I32F32::NEG_EPSILON),"-0.00000001"); - assert_eq!(format!("{:?}",I32F32::NEG_ONE),"-1.00000000"); - assert_eq!(format!("{:?}",I32F32::NEG_TWO),"-2.00000000"); - assert_eq!(format!("{:?}",I32F32::MIN),"-80000000.00000000"); + assert_eq!(format!("{:?}",F64_32::EPSILON),"0.00000001"); + assert_eq!(format!("{:?}",F64_32::ONE),"1.00000000"); + assert_eq!(format!("{:?}",F64_32::TWO),"2.00000000"); + assert_eq!(format!("{:?}",F64_32::MAX),"7fffffff.ffffffff"); + assert_eq!(format!("{:?}",F64_32::try_from(core::f64::consts::PI).unwrap()),"3.243f6a88"); + assert_eq!(format!("{:?}",F64_32::NEG_EPSILON),"-0.00000001"); + assert_eq!(format!("{:?}",F64_32::NEG_ONE),"-1.00000000"); + assert_eq!(format!("{:?}",F64_32::NEG_TWO),"-2.00000000"); + assert_eq!(format!("{:?}",F64_32::MIN),"-80000000.00000000"); } diff --git a/lib/fixed_wide/src/types.rs b/lib/fixed_wide/src/types.rs index 86944354..64c2b279 100644 --- a/lib/fixed_wide/src/types.rs +++ b/lib/fixed_wide/src/types.rs @@ -1,4 +1,7 @@ -pub type I32F32=crate::fixed::Fixed<1,32>; -pub type I64F64=crate::fixed::Fixed<2,64>; -pub type I128F128=crate::fixed::Fixed<4,128>; -pub type I256F256=crate::fixed::Fixed<8,256>; +use crate::fixed::BNUM_DIGIT_WIDTH; +pub type F64_32=crate::fixed::Fixed<{64/BNUM_DIGIT_WIDTH},32>; +pub type F128_64=crate::fixed::Fixed<{128/BNUM_DIGIT_WIDTH},64>; +pub type F192_96=crate::fixed::Fixed<{192/BNUM_DIGIT_WIDTH},96>; +pub type F256_128=crate::fixed::Fixed<{256/BNUM_DIGIT_WIDTH},128>; +pub type F320_160=crate::fixed::Fixed<{320/BNUM_DIGIT_WIDTH},160>; +pub type F512_256=crate::fixed::Fixed<{512/BNUM_DIGIT_WIDTH},256>; diff --git a/lib/fixed_wide/src/zeroes.rs b/lib/fixed_wide/src/zeroes.rs index 0bde9dd9..321bbed7 100644 --- a/lib/fixed_wide/src/zeroes.rs +++ b/lib/fixed_wide/src/zeroes.rs @@ -1,18 +1,19 @@ use crate::fixed::Fixed; +use crate::fixed::BNUM_DIGIT_WIDTH; use arrayvec::ArrayVec; use std::cmp::Ordering; macro_rules! impl_zeroes{ ($n:expr)=>{ - impl Fixed<$n,{$n*32}>{ + impl Fixed<{$n/BNUM_DIGIT_WIDTH},{$n>>1}>{ #[inline] pub fn zeroes2(a0:Self,a1:Self,a2:Self)->ArrayVec<::Output,2>{ let a2pos=match a2.cmp(&Self::ZERO){ Ordering::Greater=>true, - Ordering::Equal=>return ArrayVec::from_iter(Self::zeroes1(a0,a1).into_iter()), + Ordering::Equal=>return ArrayVec::from_iter(Self::zeroes1(a0,a1)), Ordering::Less=>false, }; - let radicand=a1*a1-a2*a0*4; + let radicand=a1*a1-((a2*a0)<<2); match radicand.cmp(&::Output::ZERO){ Ordering::Greater=>{ // using wrap because sqrt always halves the number of leading digits. @@ -21,21 +22,21 @@ macro_rules! impl_zeroes{ let planar_radicand=radicand.sqrt().[](); } //sort roots ascending and avoid taking the difference of large numbers - let zeroes=match (a2pos,Self::ZERO[(-a1-planar_radicand)/(a2*2),(a0*2)/(-a1-planar_radicand)], - (true, false)=>[(a0*2)/(-a1+planar_radicand),(-a1+planar_radicand)/(a2*2)], - (false,true )=>[(a0*2)/(-a1-planar_radicand),(-a1-planar_radicand)/(a2*2)], - (false,false)=>[(-a1+planar_radicand)/(a2*2),(a0*2)/(-a1+planar_radicand)], + let zeroes=match (a2pos,a1.is_positive()){ + (true, true )=>[(-a1-planar_radicand)/(a2<<1),(a0<<1)/(-a1-planar_radicand)], + (true, false)=>[(a0<<1)/(-a1+planar_radicand),(-a1+planar_radicand)/(a2<<1)], + (false,true )=>[(a0<<1)/(-a1-planar_radicand),(-a1-planar_radicand)/(a2<<1)], + (false,false)=>[(-a1+planar_radicand)/(a2<<1),(a0<<1)/(-a1+planar_radicand)], }; ArrayVec::from_iter(zeroes) }, - Ordering::Equal=>ArrayVec::from_iter([(a1)/(a2*-2)]), + Ordering::Equal=>ArrayVec::from_iter([(a1)/(-a2<<1)]), Ordering::Less=>ArrayVec::new_const(), } } #[inline] pub fn zeroes1(a0:Self,a1:Self)->ArrayVec<::Output,1>{ - if a1==Self::ZERO{ + if a1.is_zero(){ ArrayVec::new_const() }else{ ArrayVec::from_iter([(-a0)/(a1)]) @@ -44,10 +45,10 @@ macro_rules! impl_zeroes{ } }; } -impl_zeroes!(1); -impl_zeroes!(2); -impl_zeroes!(3); -impl_zeroes!(4); +impl_zeroes!(64); +impl_zeroes!(128); +impl_zeroes!(192); +impl_zeroes!(256); //sqrt doubles twice! //impl_zeroes!(5); //impl_zeroes!(6); diff --git a/lib/linear_ops/src/macros/fixed_wide.rs b/lib/linear_ops/src/macros/fixed_wide.rs index 1434ea66..851e5b4a 100644 --- a/lib/linear_ops/src/macros/fixed_wide.rs +++ b/lib/linear_ops/src/macros/fixed_wide.rs @@ -5,17 +5,17 @@ macro_rules! impl_fixed_wide_vector_not_const_generic { (), $n:expr ) => { - impl Vector>{ + impl Vector>3},{$n>>1}>>{ #[inline] - pub fn length(self)-> as core::ops::Mul>::Output{ + pub fn length(self)->>3},{$n>>1}> as core::ops::Mul>::Output{ self.length_squared().sqrt_unchecked() } #[inline] - pub fn with_length(self,length:U)-> as core::ops::Div< as core::ops::Mul>::Output>>::Output + pub fn with_length(self,length:U)-> as core::ops::Div<>3},{$n>>1}> as core::ops::Mul>::Output>>::Output where - fixed_wide::fixed::Fixed<$n,{$n*32}>:core::ops::Mul, + fixed_wide::fixed::Fixed<{$n>>3},{$n>>1}>:core::ops::Mul, U:Copy, - V:core::ops::Div< as core::ops::Mul>::Output>, + V:core::ops::Div<>3},{$n>>1}> as core::ops::Mul>::Output>, { self*length/self.length() } @@ -27,7 +27,7 @@ macro_rules! impl_fixed_wide_vector_not_const_generic { #[macro_export(local_inner_macros)] macro_rules! macro_4 { ( $macro: ident, $any:tt ) => { - $crate::macro_repeated!($macro,$any,1,2,3,4); + $crate::macro_repeated!($macro,$any,64,128,192,256); } } @@ -39,40 +39,40 @@ macro_rules! impl_fixed_wide_vector { // I LOVE NOT BEING ABLE TO USE CONST GENERICS $crate::macro_repeated!( impl_narrow_not_const_generic,(), - (2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1),(17,1), - (3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2), - (4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3), - (5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),(13,4),(14,4),(15,4),(16,4), - (6,5),(7,5),(8,5),(9,5),(10,5),(11,5),(12,5),(13,5),(14,5),(15,5),(16,5), - (7,6),(8,6),(9,6),(10,6),(11,6),(12,6),(13,6),(14,6),(15,6),(16,6), - (8,7),(9,7),(10,7),(11,7),(12,7),(13,7),(14,7),(15,7),(16,7), - (9,8),(10,8),(11,8),(12,8),(13,8),(14,8),(15,8),(16,8), - (10,9),(11,9),(12,9),(13,9),(14,9),(15,9),(16,9), - (11,10),(12,10),(13,10),(14,10),(15,10),(16,10), - (12,11),(13,11),(14,11),(15,11),(16,11), - (13,12),(14,12),(15,12),(16,12), - (14,13),(15,13),(16,13), - (15,14),(16,14), - (16,15) + (128,64),(192,64),(256,64),(320,64),(384,64),(448,64),(512,64),(576,64),(640,64),(704,64),(768,64),(832,64),(896,64),(960,64),(1024,64),(1088,64), + (192,128),(256,128),(320,128),(384,128),(448,128),(512,128),(576,128),(640,128),(704,128),(768,128),(832,128),(896,128),(960,128),(1024,128), + (256,192),(320,192),(384,192),(448,192),(512,192),(576,192),(640,192),(704,192),(768,192),(832,192),(896,192),(960,192),(1024,192), + (320,256),(384,256),(448,256),(512,256),(576,256),(640,256),(704,256),(768,256),(832,256),(896,256),(960,256),(1024,256), + (384,320),(448,320),(512,320),(576,320),(640,320),(704,320),(768,320),(832,320),(896,320),(960,320),(1024,320), + (448,384),(512,384),(576,384),(640,384),(704,384),(768,384),(832,384),(896,384),(960,384),(1024,384), + (512,448),(576,448),(640,448),(704,448),(768,448),(832,448),(896,448),(960,448),(1024,448), + (576,512),(640,512),(704,512),(768,512),(832,512),(896,512),(960,512),(1024,512), + (640,576),(704,576),(768,576),(832,576),(896,576),(960,576),(1024,576), + (704,640),(768,640),(832,640),(896,640),(960,640),(1024,640), + (768,704),(832,704),(896,704),(960,704),(1024,704), + (832,768),(896,768),(960,768),(1024,768), + (896,832),(960,832),(1024,832), + (960,896),(1024,896), + (1024,960) ); $crate::macro_repeated!( impl_widen_not_const_generic,(), - (1,2), - (1,3),(2,3), - (1,4),(2,4),(3,4), - (1,5),(2,5),(3,5),(4,5), - (1,6),(2,6),(3,6),(4,6),(5,6), - (1,7),(2,7),(3,7),(4,7),(5,7),(6,7), - (1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8), - (1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),(8,9), - (1,10),(2,10),(3,10),(4,10),(5,10),(6,10),(7,10),(8,10),(9,10), - (1,11),(2,11),(3,11),(4,11),(5,11),(6,11),(7,11),(8,11),(9,11),(10,11), - (1,12),(2,12),(3,12),(4,12),(5,12),(6,12),(7,12),(8,12),(9,12),(10,12),(11,12), - (1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13), - (1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14), - (1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15), - (1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16), - (1,17) + (64,128), + (64,192),(128,192), + (64,256),(128,256),(192,256), + (64,320),(128,320),(192,320),(256,320), + (64,384),(128,384),(192,384),(256,384),(320,384), + (64,448),(128,448),(192,448),(256,448),(320,448),(384,448), + (64,512),(128,512),(192,512),(256,512),(320,512),(384,512),(448,512), + (64,576),(128,576),(192,576),(256,576),(320,576),(384,576),(448,576),(512,576), + (64,640),(128,640),(192,640),(256,640),(320,640),(384,640),(448,640),(512,640),(576,640), + (64,704),(128,704),(192,704),(256,704),(320,704),(384,704),(448,704),(512,704),(576,704),(640,704), + (64,768),(128,768),(192,768),(256,768),(320,768),(384,768),(448,768),(512,768),(576,768),(640,768),(704,768), + (64,832),(128,832),(192,832),(256,832),(320,832),(384,832),(448,832),(512,832),(576,832),(640,832),(704,832),(768,832), + (64,896),(128,896),(192,896),(256,896),(320,896),(384,896),(448,896),(512,896),(576,896),(640,896),(704,896),(768,896),(832,896), + (64,960),(128,960),(192,960),(256,960),(320,960),(384,960),(448,960),(512,960),(576,960),(640,960),(704,960),(768,960),(832,960),(896,960), + (64,1024),(128,1024),(192,1024),(256,1024),(320,1024),(384,1024),(448,1024),(512,1024),(576,1024),(640,1024),(704,1024),(768,1024),(832,1024),(896,1024),(960,1024), + (64,1088) ); impl,U> fixed_wide::fixed::Wrap> for Vector { @@ -98,17 +98,17 @@ macro_rules! impl_narrow_not_const_generic{ ($lhs:expr,$rhs:expr) )=>{ paste::item!{ - impl Vector>{ + impl Vector>3},{$lhs>>1}>>{ #[inline] - pub fn [](self)->Vector>{ + pub fn [](self)->Vector>3},{$rhs>>1}>>{ self.map(|t|t.[]()) } #[inline] - pub fn [](self)->Vector,fixed_wide::fixed::NarrowError>>{ + pub fn [](self)->Vector>3},{$rhs>>1}>,fixed_wide::fixed::NarrowError>>{ self.map(|t|t.[]()) } #[inline] - pub fn [](self)->Vector>{ + pub fn [](self)->Vector>3},{$rhs>>1}>>{ self.map(|t|t.[]()) } } @@ -123,9 +123,9 @@ macro_rules! impl_widen_not_const_generic{ ($lhs:expr,$rhs:expr) )=>{ paste::item!{ - impl Vector>{ + impl Vector>3},{$lhs>>1}>>{ #[inline] - pub fn [](self)->Vector>{ + pub fn [](self)->Vector>3},{$rhs>>1}>>{ self.map(|t|t.[]()) } } diff --git a/lib/linear_ops/src/tests/fixed_wide.rs b/lib/linear_ops/src/tests/fixed_wide.rs index 7032fd07..f0c8dba9 100644 --- a/lib/linear_ops/src/tests/fixed_wide.rs +++ b/lib/linear_ops/src/tests/fixed_wide.rs @@ -1,9 +1,9 @@ use crate::types::{Matrix3,Matrix3x2,Matrix3x4,Matrix4x2,Vector3}; -type Planar64=fixed_wide::types::I32F32; -type Planar64Wide1=fixed_wide::types::I64F64; +type Planar64=fixed_wide::types::F64_32; +type Planar64Wide1=fixed_wide::types::F128_64; //type Planar64Wide2=fixed_wide::types::I128F128; -type Planar64Wide3=fixed_wide::types::I256F256; +type Planar64Wide3=fixed_wide::types::F512_256; #[test] fn wide_vec3(){ @@ -72,7 +72,7 @@ fn wide_matrix_det(){ ]); // In[2]:= Det[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}] // Out[2]= 7 - assert_eq!(m.det(),fixed_wide::fixed::Fixed::<3,96>::from(7)); + assert_eq!(m.det(),fixed_wide::types::F192_96::from(7)); } #[test] diff --git a/lib/rbx_loader/src/primitives.rs b/lib/rbx_loader/src/primitives.rs index bfd6afd4..beeb315c 100644 --- a/lib/rbx_loader/src/primitives.rs +++ b/lib/rbx_loader/src/primitives.rs @@ -519,7 +519,7 @@ pub fn unit_cylinder(face_descriptions:CubeFaceDescription)->Mesh{ (glam::vec2(-x as f32,y as f32).normalize()+1.0)/2.0 ) ); - let pos=mb.acquire_pos_id($end+vec3::int(0,-x,y).with_length(Planar64::ONE).divide().wrap_1()); + let pos=mb.acquire_pos_id($end+vec3::int(0,-x,y).with_length(Planar64::ONE).divide().wrap_64()); mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color}) }).collect(); @@ -560,9 +560,9 @@ pub fn unit_cylinder(face_descriptions:CubeFaceDescription)->Mesh{ let mut polygon_list=Vec::with_capacity(CubeFaceDescription::FACES); for $loop in -GON..GON{ // lo Z - let lz_dir=$lo_dir.with_length(Planar64::ONE).divide().wrap_1(); + let lz_dir=$lo_dir.with_length(Planar64::ONE).divide().wrap_64(); // hi Z - let hz_dir=$hi_dir.with_length(Planar64::ONE).divide().wrap_1(); + let hz_dir=$hi_dir.with_length(Planar64::ONE).divide().wrap_64(); // pos let lx_lz_pos=mb.acquire_pos_id(vec3::NEG_X+lz_dir); diff --git a/lib/rbx_loader/src/rbx.rs b/lib/rbx_loader/src/rbx.rs index 4db84acd..9974d015 100644 --- a/lib/rbx_loader/src/rbx.rs +++ b/lib/rbx_loader/src/rbx.rs @@ -31,11 +31,11 @@ fn planar64_affine3_from_roblox(cf:&rbx_dom_weak::types::CFrame,size:&rbx_dom_we Ok(Planar64Affine3::new( Planar64Mat3::from_cols([ (vec3::try_from_f32_array([cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x])? - *integer::try_from_f32(size.x/2.0)?).narrow_1().unwrap(),//.map_err(Planar64ConvertError::Narrow)? + *integer::try_from_f32(size.x/2.0)?).narrow_64().unwrap(),//.map_err(Planar64ConvertError::Narrow)? (vec3::try_from_f32_array([cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y])? - *integer::try_from_f32(size.y/2.0)?).narrow_1().unwrap(),//.map_err(Planar64ConvertError::Narrow)? + *integer::try_from_f32(size.y/2.0)?).narrow_64().unwrap(),//.map_err(Planar64ConvertError::Narrow)? (vec3::try_from_f32_array([cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z])? - *integer::try_from_f32(size.z/2.0)?).narrow_1().unwrap(),//.map_err(Planar64ConvertError::Narrow)? + *integer::try_from_f32(size.z/2.0)?).narrow_64().unwrap(),//.map_err(Planar64ConvertError::Narrow)? ]), vec3::try_from_f32_array([cf.position.x,cf.position.y,cf.position.z])? )) @@ -909,13 +909,13 @@ impl PartialMap1<'_>{ model.mesh=mesh; // avoid devide by zero but introduce more edge cases. not sure what the correct thing to do here is. if mesh_size.x!=integer::Fixed::ZERO{ - model.transform.matrix3.x_axis=(model.transform.matrix3.x_axis*2/mesh_size.x).divide().narrow_1().unwrap(); + model.transform.matrix3.x_axis=(model.transform.matrix3.x_axis*2/mesh_size.x).divide().narrow_64().unwrap(); } if mesh_size.y!=integer::Fixed::ZERO{ - model.transform.matrix3.y_axis=(model.transform.matrix3.y_axis*2/mesh_size.y).divide().narrow_1().unwrap(); + model.transform.matrix3.y_axis=(model.transform.matrix3.y_axis*2/mesh_size.y).divide().narrow_64().unwrap(); } if mesh_size.z!=integer::Fixed::ZERO{ - model.transform.matrix3.z_axis=(model.transform.matrix3.z_axis*2/mesh_size.z).divide().narrow_1().unwrap(); + model.transform.matrix3.z_axis=(model.transform.matrix3.z_axis*2/mesh_size.z).divide().narrow_64().unwrap(); } Some(model) }).chain(self.deferred_unions_deferred_attributes.into_iter().flat_map(|deferred_union_deferred_attributes|{ @@ -932,13 +932,13 @@ impl PartialMap1<'_>{ model.mesh=mesh; // avoid devide by zero but introduce more edge cases. not sure what the correct thing to do here is. if size.x!=integer::Fixed::ZERO{ - model.transform.matrix3.x_axis=(model.transform.matrix3.x_axis*2/size.x).divide().narrow_1().unwrap(); + model.transform.matrix3.x_axis=(model.transform.matrix3.x_axis*2/size.x).divide().narrow_64().unwrap(); } if size.y!=integer::Fixed::ZERO{ - model.transform.matrix3.y_axis=(model.transform.matrix3.y_axis*2/size.y).divide().narrow_1().unwrap(); + model.transform.matrix3.y_axis=(model.transform.matrix3.y_axis*2/size.y).divide().narrow_64().unwrap(); } if size.z!=integer::Fixed::ZERO{ - model.transform.matrix3.z_axis=(model.transform.matrix3.z_axis*2/size.z).divide().narrow_1().unwrap(); + model.transform.matrix3.z_axis=(model.transform.matrix3.z_axis*2/size.z).divide().narrow_64().unwrap(); } Some(model) })) diff --git a/lib/snf/src/map.rs b/lib/snf/src/map.rs index 833de375..f570be68 100644 --- a/lib/snf/src/map.rs +++ b/lib/snf/src/map.rs @@ -386,7 +386,7 @@ pub fn write_map(mut writer:W,map:strafesnet_common::map::Comple let mesh=map.meshes.get(model.mesh.get() as usize).ok_or(Error::InvalidMeshId(model.mesh))?; let mut aabb=Aabb::default(); for &pos in &mesh.unique_pos{ - aabb.grow(model.transform.transform_point3(pos).narrow_1().unwrap()); + aabb.grow(model.transform.transform_point3(pos).narrow_64().unwrap()); } Ok(((model::ModelId::new(model_id as u32),model.into()),aabb)) }).collect::,_>>()?;