7 ms·
Show HN: Rust Vector and Quaternion Lib
I use this library I made for Vectors and Quaternions in many personal projects. I've open-sourced it, in case anyone else would get use out of it.
I use this on various projects, including quadcopter firmware, a graphics engine, a cosmology simulation, and several molecular dynamics applications. No_std compatible.
- lawlessone 2y agoQuaternions, we were due our weekly quaternion post. Nice work by the way!
- deleted 2y ago[deleted]
- tux3 2y agoSounds interesting, but it's a space with a lot of different options. Have tried doing benchmarks against other vector libraries? If I'm shopping for a vector library, this is one of the pieces of information that makes the decision easier.
- mflaherty22 2y agoI'd like to see what the author's motivation was for making this, but I'm not sure benchmarks would be the first thing I look for :)
- the__alchemist 2y agoI haven't done benchmarks, but this speculation nailed it - The exact motivation is lost, but I believe I became tilted with inconsistent mixes of JPL and Hamilton quaternion operations on the popular libs at the time. Since then, I use it as a low-friction way to conserve geometrical functions among multiple projects. I.e., it's easier to just edit the code base than go through a PR process.
- zamalek 2y agono_std seems somewhat novel, which might have been another motivating factor?
- creata 2y agoI haven't benchmarked, so these opinions might be worthless, but here's how they're laid out internally. * nalgebra uses fixed-size arrays (so a Vec4 is like [[f32; 4]; 1]) * this library seems to use fields (so a Vec4 is a struct with x,y,z,w fields) * glam uses SIMD types for some types (so a Vec4 is a __m128) I think maybe glam might win for some operations, but if you want performance, people usually SIMD in the other direction when possible, like: struct Vec4 { x: __m128, y: __m128, z: __m128, w: __m128 } According to mathbench-rs[0] (which I looked at after typing this comment...) it looks like nalgebra and ultraviolet have such types. The benchmarks have "N/A" for many of the "wide" nalgebra entries though, which might indicate that nalgebra hasn't implemented many of those functions for "wide" types. [0]: https://github.com/bitshifter/mathbench-rs https://github.com/bitshifter/mathbench-rs
- Animats 2y agoThe glam guy wanted to go all aligned so that SIMD would work, but that would break so much code that he was talked out of it. Hint for language designers: when you design a new language, put this stuff, and multidimensional arrays, in the standard library. Multiple incompatible versions of such types is as bad for number-crunching as would be multiple incompatible string types for string manipulation. You want your standard numeric libraries to work on the standard types. This is part of why Matlab is so successful. You don't have to worry about this stuff.
- zevets 2y agoIt's honestly surprising so many programming languages ignore the needs of "floating point" users. Rust has ints that aren't 0, but no std type for floats that aren't NaN? In some sense, ieee754 floats are better than ints, as the float error modes have NaNs are just HW supported error tagged enum types. I think its from a CS education which treats the "naturals" as fundamental, vs an engineering background where the "reals" are fundamental, and matrix math _essential_ and people live on one side of this fence.
- vlovich123 2y ago
- exDM69 2y agoI'm using Rust (nightly) std::simd for my 3d math stuff. It doesn't come with matrix and quaternion functions but they were relatively simple to implement based on known good algorithms. But you do get basic arithmetic operators without having to implement std::ops by hand (or with macros). What was/is not pretty is adding some generics so the same code can work with f32 and f64. I did manage to get something that works but it's so ugly that I didn't want to release it. I'm sure it could be improved but what I got works well enough and I haven't needed to touch it in a few years. std::simd is quite pleasant to work with and most importantly it allows a zero cost fallback to CPU specific intrinsics when needed.
- simojo 2y agohow does it compare to nalgebra?
- kvark 2y agoThe gamedev ecosystem appears to be split between nalgebra (for Rapier users) and glam. Where does lin-alg fit?
- pttrn 2y agocgmath?
- bladeee 2y agocgmath is nice, but it uses old Rust 2015 and hasn't been updated since January 2021.
- tialaramex 2y agoI can't imagine any obvious reason I would miss Rust's 2018 edition, let alone 2024 edition, to implement linear algebra? People seemed happy enough in Fortran before I was old enough to go to school and I don't sense it's an application where I'd want async for example. A lot of other edition changes are nice when writing new thing but not helpful for an existing codebase. So, like, sure, it's 2015 edition but that's fine?
- foresterre 2y agoThere's actually an advantage to using older editions, and that is that it lowers the MSRV (minimum supported Rust version). This is especially nice for libraries, while binary project usually can just use the latest edition.
- duped 2y agoit's updated, just not on crates.io
- cwiz 2y agoThere's also bevy_math with quite large number of crates depending on it.
- 2y ago
- dsffsad 2y ago[flagged]
- ivanjermakov 2y ago> Do not run cargo fmt on this code base; the macro used to prevent duplication of code between f32 and f64 modules causes undesirable behavior. Why not use #[rustfmt::skip]?
- deleted 2y ago[deleted]
- the__alchemist 2y agoGood question. I tried marking that on several functions, but still ended up with inappropriate indents, related to the macros. Fortunately, it seems that a (relatively) recent `rustfmt` update resolved this. `fmt` now doesn't work properly, but it doesn't break the indents either.
- gibibit 2y ago> For Compatibility with no_std tgts, e.g. embedded, Use the no_std feature. Note, this is not the recommended way to use Rust feature flags. They are additive and so the correct way to make a `no_std` compatible crate is to have a `std` feature flag that conditionally enables use of the `std` library. Referring to Effective Rust: > Note that there's a trap for the unwary here: don't have a no_std feature that disables functionality requiring std (or a no_alloc feature similarly). As explained in Item 26, features need to be additive, and there's no way to combine two users of the crate where one configures no_std and one doesn't—the former will trigger the removal of code that the latter relies on. - https://www.lurklurk.org/effective-rust/no-std.html https://www.lurklurk.org/effective-rust/no-std.html
- deleted 2y ago[deleted]
- leoedin 2y agoI'm a bit confused by this. In practice you can't combine no_std and std within a single project anyway - because then the entire app is relying on the std library, so is no longer no_std. Surely if a user sets no_std as a feature, they expect that to be the case for the entire application?
- junon 2y agostd is based on core, the latter of which is available in no_std. Std is thus additive. GP comment is correct; this is how the entire ecosystem structures no_std-compatible crates.
- sapiogram 2y ago> In practice you can't combine no_std and std within a single project anyway You can with Rust features. It allows a library to conditionally compile certain parts of the code, and users of the library can decide which features to enable. If a library only uses stdlib in code gated by #[feature(std)], users can disable that flag, and use the library in no_std contexts.
- aquarin 2y agoVery nice. Are there any test covering the functionality?
- m00dy 2y agounfortunately, there are no tests in it
- moron4hire 2y agolet mut d = a.dot(b); d.normalize(); I think I found a bug in your readme. Dot product should return a scalar. I don't know Rust at all, but I've never met any languages that had a normalize method for scalars.
- the__alchemist 2y agoYou're absolutely correct
- Keyframe 2y agoI admit I haven't gone yet past the README, but I did a fair share of such programming in the past and there's always the same use-case presented which is fine for clarity, but.. ask yourself when is it that you're doing one of each (transforms, normalizations, etc.)? General use-case is many (MANY) at once, and writing an optimized code for both is vastly different.
- the__alchemist 2y agoConcur on this. Usually reaching for an approximation algorithm (FMM, Barnes Hut etc), and/or serialization and sending to a CUDA kernel. And generally using Rayon to parallelize if not on CUDA. I'm curious how to explore the space on CPU optimization (SIMD, SOA/AOS etc), but don't know anything about it.
- Keyframe 2y agoI'm curious how to explore the space on CPU optimization (SIMD, SOA/AOS etc), but don't know anything about it. as with anything in that regard. profile, profile, profile. valgrind, check cache misses and profile. calculate theoretical throughput of a cpu you're working on, like actual bandwidth of reading/writing RAM, with and without caching, and that's your high post; to try to get as close as possible to those limits. If you want to start with that, you can do just that, simple reads/writes and profile and then introduce functions and structures instead and try to reclaim speed as much as possible. graphs over profiling always help, even better graphs over profiling on commits or PRs so you can tell how you're progressing. But that's just like my opinion, man. No right/wrong way, profiling always tells the truth in the end. tl;dr; read ops for cpu; profile.
- the__alchemist 2y agoI just added a 256-bit SoA SIMD computation. Going to follow your advice and benchmark this against both plain rust, and CUDA. (f32)
- Keyframe 2y ago