From 357b4b8a757d2df33d0ec594e7d1141c9ec61efa Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Thu, 11 Dec 2025 14:12:07 +0100 Subject: [PATCH 1/8] Use constants instead of types from typenum to describe units --- Cargo.toml | 1 - src/ad.rs | 45 ++----- src/fmt.rs | 117 ++++++++-------- src/lib.rs | 350 +++++++++++++++++++++++++++++++++++++++++++++--- src/nalgebra.rs | 3 +- src/ops.rs | 55 ++++---- src/python.rs | 117 +++++++++++----- 7 files changed, 505 insertions(+), 183 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22b1125..a50c0c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ rustdoc-args = ["--html-in-header", "./src/docs-header.html"] members = ["si-units", "example/extend_quantity"] [dependencies] -typenum = "1.17" num-traits = "0.2" document-features = "0.2" ## Use N-dimensional arrays from the [ndarray] crate as value of a quantity. diff --git a/src/ad.rs b/src/ad.rs index 367bfb2..88bf1c5 100644 --- a/src/ad.rs +++ b/src/ad.rs @@ -1,11 +1,10 @@ -use super::Quantity; +use super::{Diff, Quantity}; use nalgebra::{DefaultAllocator, Dim, OMatrix, OVector, U1, allocator::Allocator}; use num_dual::{ Dual, Dual2, Dual2Vec, Dual3, DualNum, DualStruct, DualVec, Gradients, HyperDual, HyperDualVec, HyperHyperDual, Real, }; use std::ops::Sub; -use typenum::Diff; impl, U> DualStruct for Quantity { type Real = Quantity; @@ -338,32 +337,10 @@ where #[cfg(test)] mod test_num_dual { use super::*; - use crate::{Area, Length, METER, Temperature, Volume}; + use crate::{Area, Length, METER, Volume}; use approx::assert_relative_eq; use nalgebra::{SMatrix, SVector, vector}; use num_dual::{Dual64, ImplicitDerivative, ImplicitFunction}; - use typenum::{P2, P3}; - - struct MyArgs { - temperature: Temperature, - } - - impl + Copy> DualStruct for MyArgs { - type Real = MyArgs; - type Inner = MyArgs; - - fn re(&self) -> Self::Real { - MyArgs { - temperature: self.temperature.re(), - } - } - - fn from_inner(inner: &Self::Inner) -> Self { - MyArgs { - temperature: Temperature::from_inner(&inner.temperature), - } - } - } struct AreaImplicit; impl ImplicitFunction for AreaImplicit { @@ -403,27 +380,27 @@ mod test_num_dual { fn test_derivative() { let (v, dv) = first_derivative(volume, 5.0 * METER); println!("{v}\t{dv:3}"); - assert_eq!(v, 125.0 * METER.powi::()); - assert_eq!(dv, 75.0 * METER.powi::()); + assert_eq!(v, 125.0 * METER.powi::<3>()); + assert_eq!(dv, 75.0 * METER.powi::<2>()); let (v, dv, d2v) = second_derivative(volume, 5.0 * METER); println!("{v}\t{dv:3}\t\t{d2v}"); - assert_eq!(v, 125.0 * METER.powi::(),); - assert_eq!(dv, 75.0 * METER.powi::(),); + assert_eq!(v, 125.0 * METER.powi::<3>(),); + assert_eq!(dv, 75.0 * METER.powi::<2>(),); assert_eq!(d2v, 30.0 * METER); let (v, dv_dx, dv_dh, d2v) = second_partial_derivative(volume2, (5.0 * METER, 20.0 * METER)); println!("{v}\t{dv_dx:3}\t{dv_dh:3}\t{d2v}"); - assert_eq!(v, 500.0 * METER.powi::(),); - assert_eq!(dv_dx, 200.0 * METER.powi::(),); - assert_eq!(dv_dh, 25.0 * METER.powi::(),); + assert_eq!(v, 500.0 * METER.powi::<3>(),); + assert_eq!(dv_dx, 200.0 * METER.powi::<2>(),); + assert_eq!(dv_dh, 25.0 * METER.powi::<2>(),); assert_eq!(d2v, 10.0 * METER); let (v, dv, d2v, d3v) = third_derivative(volume, 5.0 * METER); println!("{v}\t{dv:3}\t\t{d2v}\t{d3v}"); - assert_eq!(v, 125.0 * METER.powi::(),); - assert_eq!(dv, 75.0 * METER.powi::(),); + assert_eq!(v, 125.0 * METER.powi::<3>(),); + assert_eq!(dv, 75.0 * METER.powi::<2>(),); assert_eq!(d2v, 30.0 * METER); assert_eq!(d3v.into_value(), 6.0); } diff --git a/src/fmt.rs b/src/fmt.rs index 6b96098..d40d646 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -4,24 +4,23 @@ use ndarray::{Array, Dimension}; use std::collections::HashMap; use std::fmt; use std::sync::LazyLock; -use typenum::{N1, N2, N3, P2, P3, P4, Quot}; const UNIT_SYMBOLS: [&str; 7] = ["s", "m", "kg", "A", "K", "mol", "cd"]; impl< Inner: fmt::Debug, - T: Integer, - L: Integer, - M: Integer, - I: Integer, - THETA: Integer, - N: Integer, - J: Integer, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, > fmt::Debug for Quantity> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f)?; - let unit = [T::I8, L::I8, M::I8, I::I8, THETA::I8, N::I8, J::I8] + let unit = [T, L, M, I, THETA, N, J] .iter() .zip(UNIT_SYMBOLS.iter()) .filter_map(|(&u, &s)| match u { @@ -48,8 +47,8 @@ pub(crate) trait PrintUnit { } macro_rules! impl_fmt { - ($t:ident, $l:ident, $m:ident, $i:ident, $theta:ident, $n:ident, $unit:expr, $symbol:expr, $has_prefix:expr) => { - impl fmt::LowerExp for Quantity> + ($t:expr, $l:expr, $m:expr, $i:expr, $theta:expr, $n:expr, $unit:expr, $symbol:expr, $has_prefix:expr) => { + impl fmt::LowerExp for Quantity> where for<'a> &'a T: Div, for<'a> Quot<&'a T, f64>: fmt::LowerExp, @@ -60,7 +59,7 @@ macro_rules! impl_fmt { } } - impl fmt::UpperExp for Quantity> + impl fmt::UpperExp for Quantity> where for<'a> &'a T: Div, for<'a> Quot<&'a T, f64>: fmt::UpperExp, @@ -73,7 +72,7 @@ macro_rules! impl_fmt { #[cfg(feature = "ndarray")] impl fmt::Display - for Quantity, SIUnit<$t, $l, $m, $i, $theta, $n, Z0>> + for Quantity, SIUnit<$t, $l, $m, $i, $theta, $n, 0>> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (self / $unit).into_value().fmt(f)?; @@ -81,7 +80,7 @@ macro_rules! impl_fmt { } } - impl fmt::Display for Quantity> { + impl fmt::Display for Quantity> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (value, prefix) = get_prefix((self / $unit).into_value(), $has_prefix); if !((1e-2..1e4).contains(&value.abs()) || value == 0.0) { @@ -94,30 +93,30 @@ macro_rules! impl_fmt { } #[cfg(feature = "python")] - impl PrintUnit for Quantity> { + impl PrintUnit for Quantity> { const UNIT: &'static str = $symbol; } }; } -impl_fmt!(P1, Z0, Z0, Z0, Z0, Z0, SECOND, "s", Some(KILO)); -impl_fmt!(Z0, P1, Z0, Z0, Z0, Z0, METER, "m", Some(MEGA)); -impl_fmt!(Z0, Z0, P1, Z0, Z0, Z0, GRAM, "g", Some(MEGA)); -impl_fmt!(Z0, Z0, Z0, Z0, Z0, P1, MOL, "mol", Some(MEGA)); -impl_fmt!(Z0, Z0, Z0, Z0, P1, Z0, KELVIN, "K", None); -impl_fmt!(N1, Z0, Z0, Z0, Z0, Z0, HERTZ, "Hz", Some(PETA)); -impl_fmt!(N2, P1, P1, Z0, Z0, Z0, NEWTON, "N", Some(PETA)); -impl_fmt!(N2, N1, P1, Z0, Z0, Z0, PASCAL, "Pa", Some(PETA)); -impl_fmt!(N2, P2, P1, Z0, Z0, Z0, JOULE, "J", Some(PETA)); -impl_fmt!(N3, P2, P1, Z0, Z0, Z0, WATT, "W", Some(PETA)); -impl_fmt!(P1, Z0, Z0, P1, Z0, Z0, COULOMB, "C", None); -impl_fmt!(N3, P2, P1, N1, Z0, Z0, VOLT, "V", Some(PETA)); -impl_fmt!(P4, N2, N1, P2, Z0, Z0, FARAD, "F", Some(PETA)); -impl_fmt!(N3, P2, P1, N2, Z0, Z0, OHM, "Ω", Some(PETA)); -impl_fmt!(P3, N2, N1, P2, Z0, Z0, SIEMENS, "S", Some(PETA)); -impl_fmt!(N2, P2, P1, N1, Z0, Z0, WEBER, "Wb", Some(PETA)); -impl_fmt!(N2, Z0, P1, N1, Z0, Z0, TESLA, "T", Some(PETA)); -impl_fmt!(N2, P2, P1, N2, Z0, Z0, HENRY, "H", Some(PETA)); +impl_fmt!(1, 0, 0, 0, 0, 0, SECOND, "s", Some(KILO)); +impl_fmt!(0, 1, 0, 0, 0, 0, METER, "m", Some(MEGA)); +impl_fmt!(0, 0, 1, 0, 0, 0, GRAM, "g", Some(MEGA)); +impl_fmt!(0, 0, 0, 0, 0, 1, MOL, "mol", Some(MEGA)); +impl_fmt!(0, 0, 0, 0, 1, 0, KELVIN, "K", None); +impl_fmt!(-1, 0, 0, 0, 0, 0, HERTZ, "Hz", Some(PETA)); +impl_fmt!(-2, 1, 1, 0, 0, 0, NEWTON, "N", Some(PETA)); +impl_fmt!(-2, -1, 1, 0, 0, 0, PASCAL, "Pa", Some(PETA)); +impl_fmt!(-2, 2, 1, 0, 0, 0, JOULE, "J", Some(PETA)); +impl_fmt!(-3, 2, 1, 0, 0, 0, WATT, "W", Some(PETA)); +impl_fmt!(1, 0, 0, 1, 0, 0, COULOMB, "C", None); +impl_fmt!(-3, 2, 1, -1, 0, 0, VOLT, "V", Some(PETA)); +impl_fmt!(4, -2, -1, 2, 0, 0, FARAD, "F", Some(PETA)); +impl_fmt!(-3, 2, 1, -2, 0, 0, OHM, "Ω", Some(PETA)); +impl_fmt!(3, -2, -1, 2, 0, 0, SIEMENS, "S", Some(PETA)); +impl_fmt!(-2, 2, 1, -1, 0, 0, WEBER, "Wb", Some(PETA)); +impl_fmt!(-2, 0, 1, -1, 0, 0, TESLA, "T", Some(PETA)); +impl_fmt!(-2, 2, 1, -2, 0, 0, HENRY, "H", Some(PETA)); const M2: Area = Quantity(1.0, PhantomData); const M3: Volume = Quantity(1.0, PhantomData); @@ -127,32 +126,32 @@ const JKGK: SpecificEntropy = Quantity(1.0, PhantomData); const WMK: ThermalConductivity = Quantity(1.0, PhantomData); const GS: MassFlowRate = Quantity(1e-3, PhantomData); -impl_fmt!(Z0, N3, Z0, Z0, Z0, P1, MOL / M3, "mol/m³", Some(MEGA)); -impl_fmt!(Z0, N2, Z0, Z0, Z0, P1, MOL / M2, "mol/m²", Some(MEGA)); -impl_fmt!(Z0, N1, Z0, Z0, Z0, P1, MOL / METER, "mol/m", Some(MEGA)); -impl_fmt!(Z0, P3, Z0, Z0, Z0, N1, M3 / MOL, "m³/mol", None); -impl_fmt!(Z0, P3, Z0, Z0, N1, N1, M3 / MOL / KELVIN, "m³/mol/K", None); -impl_fmt!(Z0, N3, P1, Z0, Z0, Z0, GRAM / M3, "g/m³", Some(MEGA)); -impl_fmt!(N2, Z0, P1, Z0, Z0, Z0, NEWTON / METER, "N/m", Some(PETA)); -impl_fmt!(N1, P2, P1, Z0, Z0, Z0, JOULE * SECOND, "J*s", Some(PETA)); -impl_fmt!(N2, P2, P1, Z0, Z0, N1, JOULE / MOL, "J/mol", Some(PETA)); -impl_fmt!(N2, P2, P1, Z0, N1, Z0, JOULE / KELVIN, "J/K", Some(PETA)); -impl_fmt!(N2, P2, P1, Z0, N1, N1, JMK, "J/mol/K", Some(PETA)); -impl_fmt!(N2, P2, Z0, Z0, Z0, Z0, JOULE / KG, "J/kg", Some(PETA)); -impl_fmt!(N2, P2, Z0, Z0, N1, Z0, JKGK, "J/kg/K", Some(PETA)); -impl_fmt!(N1, N1, P1, Z0, Z0, Z0, PASCAL * SECOND, "Pa*s", Some(PETA)); -impl_fmt!(N1, P1, Z0, Z0, Z0, Z0, METER / SECOND, "m/s", Some(MEGA)); -impl_fmt!(N1, P2, Z0, Z0, Z0, Z0, M2 / SECOND, "m²/s", None); -impl_fmt!(N3, P1, P1, Z0, N1, Z0, WMK, "W/m/K", Some(PETA)); -impl_fmt!(Z0, Z0, P1, Z0, Z0, N1, GRAM / MOL, "g/mol", Some(MEGA)); -impl_fmt!(Z0, P2, Z0, Z0, Z0, Z0, M2, "m²", None); -impl_fmt!(Z0, P3, Z0, Z0, Z0, Z0, M3, "m³", None); -impl_fmt!(N1, P3, N1, Z0, Z0, Z0, M3 / KG / SECOND, "m³/kg/s²", None); -impl_fmt!(N3, P2, P1, Z0, N1, Z0, WATT / KELVIN, "W/K", None); -impl_fmt!(N3, Z0, P1, Z0, N1, Z0, WMK / METER, "W/m²/K", None); -impl_fmt!(N3, Z0, P1, Z0, Z0, Z0, WATT / M2, "W/m²", None); -impl_fmt!(N1, Z0, P1, Z0, Z0, Z0, GS, "g/s", Some(MEGA)); -impl_fmt!(N1, N2, P1, Z0, Z0, Z0, GS / M2, "g/m²/s", Some(MEGA)); +impl_fmt!(0, -3, 0, 0, 0, 1, MOL / M3, "mol/m³", Some(MEGA)); +impl_fmt!(0, -2, 0, 0, 0, 1, MOL / M2, "mol/m²", Some(MEGA)); +impl_fmt!(0, -1, 0, 0, 0, 1, MOL / METER, "mol/m", Some(MEGA)); +impl_fmt!(0, 3, 0, 0, 0, -1, M3 / MOL, "m³/mol", None); +impl_fmt!(0, 3, 0, 0, -1, -1, M3 / MOL / KELVIN, "m³/mol/K", None); +impl_fmt!(0, -3, 1, 0, 0, 0, GRAM / M3, "g/m³", Some(MEGA)); +impl_fmt!(-2, 0, 1, 0, 0, 0, NEWTON / METER, "N/m", Some(PETA)); +impl_fmt!(-1, 2, 1, 0, 0, 0, JOULE * SECOND, "J*s", Some(PETA)); +impl_fmt!(-2, 2, 1, 0, 0, -1, JOULE / MOL, "J/mol", Some(PETA)); +impl_fmt!(-2, 2, 1, 0, -1, 0, JOULE / KELVIN, "J/K", Some(PETA)); +impl_fmt!(-2, 2, 1, 0, -1, -1, JMK, "J/mol/K", Some(PETA)); +impl_fmt!(-2, 2, 0, 0, 0, 0, JOULE / KG, "J/kg", Some(PETA)); +impl_fmt!(-2, 2, 0, 0, -1, 0, JKGK, "J/kg/K", Some(PETA)); +impl_fmt!(-1, -1, 1, 0, 0, 0, PASCAL * SECOND, "Pa*s", Some(PETA)); +impl_fmt!(-1, 1, 0, 0, 0, 0, METER / SECOND, "m/s", Some(MEGA)); +impl_fmt!(-1, 2, 0, 0, 0, 0, M2 / SECOND, "m²/s", None); +impl_fmt!(-3, 1, 1, 0, -1, 0, WMK, "W/m/K", Some(PETA)); +impl_fmt!(0, 0, 1, 0, 0, -1, GRAM / MOL, "g/mol", Some(MEGA)); +impl_fmt!(0, 2, 0, 0, 0, 0, M2, "m²", None); +impl_fmt!(0, 3, 0, 0, 0, 0, M3, "m³", None); +impl_fmt!(-1, 3, -1, 0, 0, 0, M3 / KG / SECOND, "m³/kg/s²", None); +impl_fmt!(-3, 2, 1, 0, -1, 0, WATT / KELVIN, "W/K", None); +impl_fmt!(-3, 0, 1, 0, -1, 0, WMK / METER, "W/m²/K", None); +impl_fmt!(-3, 0, 1, 0, 0, 0, WATT / M2, "W/m²", None); +impl_fmt!(-1, 0, 1, 0, 0, 0, GS, "g/s", Some(MEGA)); +impl_fmt!(-1, -2, 1, 0, 0, 0, GS / M2, "g/m²/s", Some(MEGA)); fn get_prefix(value: f64, has_prefix: Option) -> (f64, &'static str) { if let Some(p) = has_prefix { diff --git a/src/lib.rs b/src/lib.rs index bb9f58f..f740b84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,9 +91,8 @@ //! Calculate pressure of an ideal gas. //! ``` //! # use quantity::*; -//! # use typenum::P3; //! let temperature = 25.0 * CELSIUS; -//! let volume = 1.5 * METER.powi::(); +//! let volume = 1.5 * METER.powi::<3>(); //! let moles = 75.0 * MOL; //! let pressure = moles * RGAS * temperature / volume; //! println!("{:.5}", pressure); // 123.94785 kPa @@ -102,11 +101,10 @@ //! Calculate the gravitational pull of the moon on the earth. //! ``` //! # use quantity::*; -//! # use typenum::P2; //! let mass_earth = 5.9724e24 * KILOGRAM; //! let mass_moon = 7.346e22 * KILOGRAM; //! let distance = 383.398 * KILO * METER; -//! let force = G * mass_earth * mass_moon / distance.powi::(); +//! let force = G * mass_earth * mass_moon / distance.powi::<2>(); //! println!("{:.5e}", force); // 1.99208e26 N //! ``` //! @@ -116,9 +114,8 @@ //! # #[cfg(feature = "ndarray")] //! # { //! # use quantity::*; -//! # use typenum::P2; //! let z = Length::linspace(1.0 * METER, 70.0 * KILO * METER, 10); -//! let g = 9.81 * METER / SECOND.powi::(); +//! let g = 9.81 * METER / SECOND.powi::<2>(); //! let m = 28.949 * GRAM / MOL; //! let t = 10.0 * CELSIUS; //! let p0 = BAR; @@ -142,11 +139,11 @@ //! Interoperability with other crates can be achieved by activating the following features: #![doc = document_features::document_features!()] #![warn(clippy::all)] +#![expect(clippy::neg_multiply)] #[cfg(feature = "ndarray")] use ndarray::{Array, ArrayBase, Data, Dimension}; use std::marker::PhantomData; -use std::ops::{Deref, Div, Mul}; -use typenum::{ATerm, Diff, Integer, N1, N2, Negate, P1, P3, Quot, Sum, TArr, Z0}; +use std::ops::{Add, Deref, Div, Mul, Neg, Sub}; #[cfg(feature = "num-dual")] pub mod ad; @@ -159,22 +156,333 @@ mod ops; #[cfg(feature = "python")] mod python; -pub type SIUnit = - TArr>>>>>>; +type Sum = >::Output; +type Diff = >::Output; +type Negate = ::Output; +type Prod = >::Output; +type Quot = >::Output; + +pub struct Const; + +macro_rules! impl_add { + ($a:expr; $($b:expr),*) => { + $( + impl_add!($a, $b); + )* + }; + ($a:expr, $b:expr) => { + impl Add> for Const<$a> { + type Output = Const<{ $a + $b }>; + + fn add(self, _: Const<$b>) -> Self::Output { + Const + } + } + }; +} + +impl_add!(-6; 0, 1, 2, 3, 4, 5, 6); +impl_add!(-5; -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(-4; -2, -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(-3; -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(-2; -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(-1; -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(0; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(1; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); +impl_add!(2; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4); +impl_add!(3; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3); +impl_add!(4; -6, -5, -4, -3, -2, -1, 0, 1, 2); +impl_add!(5; -6, -5, -4, -3, -2, -1, 0, 1); +impl_add!(6; -6, -5, -4, -3, -2, -1, 0); + +macro_rules! impl_neg { + ($a:expr) => { + impl Neg for Const<$a> { + type Output = Const<{ -$a }>; + + fn neg(self) -> Self::Output { + Const + } + } + }; + ($($a:expr),+) => { + impl_neg!(0); + $( + impl_neg!($a); + impl_neg!({-$a}); + )+ + }; +} + +impl_neg!(1, 2, 3, 4, 5, 6); + +impl Sub> for Const +where + Const: Neg, + Const: Add>, Output = Const>, + Const: Add, Output = Const>, +{ + type Output = Const; + + fn sub(self, _: Const) -> Self::Output { + Const + } +} + +macro_rules! impl_mul { + ($a:expr; $($b:expr),*) => { + $( + impl_mul!($a, $b); + )* + }; + ($a:expr, $b:expr) => { + impl Mul> for Const<$a> { + type Output = Const<{ $a * $b }>; + + fn mul(self, _: Const<$b>) -> Self::Output { + Const + } + } + }; +} + +impl_mul!(-3; -2, 2); +impl_mul!(-2; -3, -2, 2, 3); +impl_mul!(-1; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); +impl_mul!(0; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); +impl_mul!(1; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); +impl_mul!(2; -3, -2, 2, 3); +impl_mul!(3; -2, 2); + +macro_rules! impl_div { + ($a:expr; $($b:expr),*) => { + $( + impl_div!($a, $b); + )* + }; + ($a:expr, $b:expr) => { + impl Div> for Const<$a> { + type Output = Const<{ $a / $b }>; + + fn div(self, _: Const<$b>) -> Self::Output { + Const + } + } + }; +} + +impl_div!(-6; -6, -3, -2, 2, 3, 6); +impl_div!(-5; -5, 5); +impl_div!(-4; -4, -2, 2, 4); +impl_div!(-3; -3, 3); +impl_div!(-2; -2, 2); +impl_div!(0; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); +impl_div!(2; -2, 2); +impl_div!(3; -3, 3); +impl_div!(4; -4, -2, 2, 4); +impl_div!(5; -5, 5); +impl_div!(6; -6, -3, -2, 2, 3, 6); + +#[derive(Clone, Copy)] +pub struct SIUnit< + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, +>; + +impl< + const T1: i8, + const L1: i8, + const M1: i8, + const I1: i8, + const THETA1: i8, + const N1: i8, + const J1: i8, + const T2: i8, + const L2: i8, + const M2: i8, + const I2: i8, + const THETA2: i8, + const N2: i8, + const J2: i8, + const T3: i8, + const L3: i8, + const M3: i8, + const I3: i8, + const THETA3: i8, + const N3: i8, + const J3: i8, +> Add> for SIUnit +where + Const: Add, Output = Const>, + Const: Add, Output = Const>, + Const: Add, Output = Const>, + Const: Add, Output = Const>, + Const: Add, Output = Const>, + Const: Add, Output = Const>, + Const: Add, Output = Const>, +{ + type Output = SIUnit; + + fn add(self, _: SIUnit) -> Self::Output { + SIUnit + } +} + +impl< + const T1: i8, + const L1: i8, + const M1: i8, + const I1: i8, + const THETA1: i8, + const N1: i8, + const J1: i8, + const T2: i8, + const L2: i8, + const M2: i8, + const I2: i8, + const THETA2: i8, + const N2: i8, + const J2: i8, +> Neg for SIUnit +where + Const: Neg>, + Const: Neg>, + Const: Neg>, + Const: Neg>, + Const: Neg>, + Const: Neg>, + Const: Neg>, +{ + type Output = SIUnit; + + fn neg(self) -> Self::Output { + SIUnit + } +} + +impl< + const T1: i8, + const L1: i8, + const M1: i8, + const I1: i8, + const THETA1: i8, + const N1: i8, + const J1: i8, + const T2: i8, + const L2: i8, + const M2: i8, + const I2: i8, + const THETA2: i8, + const N2: i8, + const J2: i8, + const T3: i8, + const L3: i8, + const M3: i8, + const I3: i8, + const THETA3: i8, + const N3: i8, + const J3: i8, +> Sub> for SIUnit +where + Const: Sub, Output = Const>, + Const: Sub, Output = Const>, + Const: Sub, Output = Const>, + Const: Sub, Output = Const>, + Const: Sub, Output = Const>, + Const: Sub, Output = Const>, + Const: Sub, Output = Const>, +{ + type Output = SIUnit; + + fn sub(self, _: SIUnit) -> Self::Output { + SIUnit + } +} + +impl< + const T1: i8, + const L1: i8, + const M1: i8, + const I1: i8, + const THETA1: i8, + const N1: i8, + const J1: i8, + const T2: i8, + const L2: i8, + const M2: i8, + const I2: i8, + const THETA2: i8, + const N2: i8, + const J2: i8, + const E: i8, +> Mul> for SIUnit +where + Const: Mul, Output = Const>, + Const: Mul, Output = Const>, + Const: Mul, Output = Const>, + Const: Mul, Output = Const>, + Const: Mul, Output = Const>, + Const: Mul, Output = Const>, + Const: Mul, Output = Const>, +{ + type Output = SIUnit; + + fn mul(self, _: Const) -> Self::Output { + SIUnit + } +} + +impl< + const T1: i8, + const L1: i8, + const M1: i8, + const I1: i8, + const THETA1: i8, + const N1: i8, + const J1: i8, + const T2: i8, + const L2: i8, + const M2: i8, + const I2: i8, + const THETA2: i8, + const N2: i8, + const J2: i8, + const E: i8, +> Div> for SIUnit +where + Const: Div, Output = Const>, + Const: Div, Output = Const>, + Const: Div, Output = Const>, + Const: Div, Output = Const>, + Const: Div, Output = Const>, + Const: Div, Output = Const>, + Const: Div, Output = Const>, +{ + type Output = SIUnit; + + fn div(self, _: Const) -> Self::Output { + SIUnit + } +} /// Physical quantity with compile-time checked unit. #[derive(Clone, Copy)] #[repr(transparent)] pub struct Quantity(T, PhantomData); -pub type _Dimensionless = SIUnit; -pub type _Time = SIUnit; -pub type _Length = SIUnit; -pub type _Mass = SIUnit; -pub type _Current = SIUnit; -pub type _Temperature = SIUnit; -pub type _Moles = SIUnit; -pub type _LuminousIntensity = SIUnit; +pub type _Dimensionless = SIUnit<0, 0, 0, 0, 0, 0, 0>; +pub type _Time = SIUnit<1, 0, 0, 0, 0, 0, 0>; +pub type _Length = SIUnit<0, 1, 0, 0, 0, 0, 0>; +pub type _Mass = SIUnit<0, 0, 1, 0, 0, 0, 0>; +pub type _Current = SIUnit<0, 0, 0, 1, 0, 0, 0>; +pub type _Temperature = SIUnit<0, 0, 0, 0, 1, 0, 0>; +pub type _Moles = SIUnit<0, 0, 0, 0, 0, 1, 0>; +pub type _LuminousIntensity = SIUnit<0, 0, 0, 0, 0, 0, 1>; pub type Dimensionless = Quantity; pub type Time = Quantity; @@ -352,11 +660,9 @@ pub const QE: Charge = Quantity(1.602176634e-19, PhantomData); /// Speed of light $\\left(c=299792458\\,\\frac{\text{m}}{\text{s}}\\right)$ pub const CLIGHT: Velocity = Quantity(299792458.0, PhantomData); /// Luminous efficacy of $540\\,\text{THz}$ radiation $\\left(K_\text{cd}=683\\,\\frac{\text{lm}}{\text{W}}\\right)$ -#[expect(clippy::type_complexity)] -pub const KCD: Quantity> = Quantity(683.0, PhantomData); +pub const KCD: Quantity> = Quantity(683.0, PhantomData); /// Gravitational constant $\\left(G=6.6743\\times 10^{-11}\\,\\frac{\text{m}^3}{\text{kg}\cdot\text{s}^2}\\right)$ -#[expect(clippy::type_complexity)] -pub const G: Quantity> = Quantity(6.6743e-11, PhantomData); +pub const G: Quantity> = Quantity(6.6743e-11, PhantomData); /// Prefix quecto $\\left(\text{q}=10^{-30}\\right)$ pub const QUECTO: f64 = 1e-30; diff --git a/src/nalgebra.rs b/src/nalgebra.rs index aa6014d..dc9c8fc 100644 --- a/src/nalgebra.rs +++ b/src/nalgebra.rs @@ -1,11 +1,10 @@ -use super::Quantity; +use super::{Quantity, Sum}; use nalgebra::allocator::Allocator; use nalgebra::constraint::{DimEq, ShapeConstraint}; use nalgebra::{ClosedAddAssign, ClosedMulAssign, DMatrix, DefaultAllocator, Dim, OMatrix, Scalar}; use num_traits::Zero; use std::marker::PhantomData; use std::ops::Add; -use typenum::Sum; impl Quantity, U> where diff --git a/src/ops.rs b/src/ops.rs index 8aaa9b1..9f7a85f 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1,4 +1,4 @@ -use super::Quantity; +use super::{Const, Diff, Negate, Prod, Quantity, Quot, Sum}; #[cfg(feature = "approx")] use approx::{AbsDiffEq, RelativeEq}; #[cfg(feature = "nalgebra")] @@ -12,7 +12,6 @@ use num_dual::DualNum; use num_traits::{Inv, Signed}; use std::marker::PhantomData; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use typenum::{Diff, Integer, Negate, P2, P3, Prod, Quot, Sum}; // Multiplication impl Mul> for Quantity @@ -372,15 +371,14 @@ impl Quantity { /// ``` /// # use quantity::METER; /// # use approx::assert_relative_eq; - /// # use typenum::P2; /// let x = 3.0 * METER; - /// assert_relative_eq!(x.powi::(), 9.0 * METER * METER); + /// assert_relative_eq!(x.powi::<2>(), 9.0 * METER * METER); /// ``` - pub fn powi(self) -> Quantity> + pub fn powi(self) -> Quantity>> where - U: Mul, + U: Mul>, { - Quantity(self.0.powi(E::I32), PhantomData) + Quantity(self.0.powi(E as i32), PhantomData) } /// Calculate the square root of self. @@ -392,9 +390,9 @@ impl Quantity { /// let x = 9.0 * METER * METER; /// assert_relative_eq!(x.sqrt(), 3.0 * METER); /// ``` - pub fn sqrt(self) -> Quantity> + pub fn sqrt(self) -> Quantity>> where - U: Div, + U: Div>, { Quantity(self.0.sqrt(), PhantomData) } @@ -408,9 +406,9 @@ impl Quantity { /// let x = 27.0 * METER * METER * METER; /// assert_relative_eq!(x.cbrt(), 3.0 * METER); /// ``` - pub fn cbrt(self) -> Quantity> + pub fn cbrt(self) -> Quantity>> where - U: Div, + U: Div>, { Quantity(self.0.cbrt(), PhantomData) } @@ -421,15 +419,14 @@ impl Quantity { /// ``` /// # use quantity::METER; /// # use approx::assert_relative_eq; - /// # use typenum::P4; /// let x = 81.0 * METER * METER * METER * METER; - /// assert_relative_eq!(x.root::(), 3.0 * METER); + /// assert_relative_eq!(x.root::<4>(), 3.0 * METER); /// ``` - pub fn root(self) -> Quantity> + pub fn root(self) -> Quantity>> where - U: Div, + U: Div>, { - Quantity(self.0.powf(1.0 / R::I32 as f64), PhantomData) + Quantity(self.0.powf(1.0 / R as f64), PhantomData) } } @@ -441,15 +438,14 @@ impl, U> Quantity { /// ``` /// # use quantity::METER; /// # use approx::assert_relative_eq; - /// # use typenum::P2; /// let x = 3.0 * METER; - /// assert_relative_eq!(x.powi::(), 9.0 * METER * METER); + /// assert_relative_eq!(x.powi::<2>(), 9.0 * METER * METER); /// ``` - pub fn powi(self) -> Quantity> + pub fn powi(self) -> Quantity>> where - U: Mul, + U: Mul>, { - Quantity(self.0.powi(E::I32), PhantomData) + Quantity(self.0.powi(E as i32), PhantomData) } /// Calculate the square root of self. @@ -461,9 +457,9 @@ impl, U> Quantity { /// let x = 9.0 * METER * METER; /// assert_relative_eq!(x.sqrt(), 3.0 * METER); /// ``` - pub fn sqrt(self) -> Quantity> + pub fn sqrt(self) -> Quantity>> where - U: Div, + U: Div>, { Quantity(self.0.sqrt(), PhantomData) } @@ -477,9 +473,9 @@ impl, U> Quantity { /// let x = 27.0 * METER * METER * METER; /// assert_relative_eq!(x.cbrt(), 3.0 * METER); /// ``` - pub fn cbrt(self) -> Quantity> + pub fn cbrt(self) -> Quantity>> where - U: Div, + U: Div>, { Quantity(self.0.cbrt(), PhantomData) } @@ -490,15 +486,14 @@ impl, U> Quantity { /// ``` /// # use quantity::METER; /// # use approx::assert_relative_eq; - /// # use typenum::P4; /// let x = 81.0 * METER * METER * METER * METER; - /// assert_relative_eq!(x.root::(), 3.0 * METER); + /// assert_relative_eq!(x.root::<4>(), 3.0 * METER); /// ``` - pub fn root(self) -> Quantity> + pub fn root(self) -> Quantity>> where - U: Div, + U: Div>, { - Quantity(self.0.powf(1.0 / R::I32 as f64), PhantomData) + Quantity(self.0.powf(1.0 / R as f64), PhantomData) } } diff --git a/src/python.rs b/src/python.rs index 45551b9..9fd2d45 100644 --- a/src/python.rs +++ b/src/python.rs @@ -12,7 +12,6 @@ use numpy::PyReadonlyArray; use numpy::{PyReadonlyArray1, PyReadonlyArray2, ToPyArray}; use pyo3::{exceptions::PyValueError, prelude::*}; use std::{marker::PhantomData, sync::LazyLock}; -use typenum::Integer; static SIOBJECT: LazyLock> = LazyLock::new(|| { Python::attach(|py| { @@ -24,15 +23,23 @@ static SIOBJECT: LazyLock> = LazyLock::new(|| { }) }); -impl<'py, T: Integer, L: Integer, M: Integer, I: Integer, THETA: Integer, N: Integer, J: Integer> - IntoPyObject<'py> for Quantity> +impl< + 'py, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, +> IntoPyObject<'py> for Quantity> { type Target = PyAny; type Output = Bound<'py, PyAny>; type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> PyResult> { - let unit = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit = [L, M, T, I, N, THETA, J]; SIOBJECT.bind(py).call1((self.0, unit)) } } @@ -40,13 +47,13 @@ impl<'py, T: Integer, L: Integer, M: Integer, I: Integer, THETA: Integer, N: Int #[cfg(feature = "ndarray")] impl< 'py, - T: Integer, - L: Integer, - M: Integer, - I: Integer, - THETA: Integer, - N: Integer, - J: Integer, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, D: Dimension, > IntoPyObject<'py> for Quantity, SIUnit> { @@ -55,44 +62,68 @@ impl< type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> PyResult> { - let unit = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit = [L, M, T, I, N, THETA, J]; let value = self.0.into_pyarray(py).into_any(); SIOBJECT.bind(py).call1((value, unit)) } } #[cfg(feature = "nalgebra")] -impl<'py, T: Integer, L: Integer, M: Integer, I: Integer, THETA: Integer, N: Integer, J: Integer> - IntoPyObject<'py> for Quantity, SIUnit> +impl< + 'py, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, +> IntoPyObject<'py> for Quantity, SIUnit> { type Target = PyAny; type Output = Bound<'py, PyAny>; type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> PyResult> { - let unit = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit = [L, M, T, I, N, THETA, J]; let value = self.0.to_pyarray(py).into_any(); SIOBJECT.bind(py).call1((value, unit)) } } #[cfg(feature = "nalgebra")] -impl<'py, T: Integer, L: Integer, M: Integer, I: Integer, THETA: Integer, N: Integer, J: Integer> - IntoPyObject<'py> for Quantity, SIUnit> +impl< + 'py, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, +> IntoPyObject<'py> for Quantity, SIUnit> { type Target = PyAny; type Output = Bound<'py, PyAny>; type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> PyResult> { - let unit = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit = [L, M, T, I, N, THETA, J]; let value = numpy::PyArray1::from_slice(py, self.0.data.as_vec()).into_any(); SIOBJECT.bind(py).call1((value, unit)) } } -impl<'py, T: Integer, L: Integer, M: Integer, I: Integer, THETA: Integer, N: Integer, J: Integer> - FromPyObject<'_, 'py> for Quantity> +impl< + 'py, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, +> FromPyObject<'_, 'py> for Quantity> where Self: PrintUnit, { @@ -108,7 +139,7 @@ where ob.call_method0("__repr__")? ))); }; - let unit_into = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit_into = [L, M, T, I, N, THETA, J]; if unit_into == unit_from { Ok(Quantity(value, PhantomData)) } else { @@ -124,13 +155,13 @@ where #[cfg(feature = "ndarray")] impl< 'py, - T: Integer, - L: Integer, - M: Integer, - I: Integer, - THETA: Integer, - N: Integer, - J: Integer, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, D: Dimension, > FromPyObject<'_, 'py> for Quantity, SIUnit> where @@ -149,7 +180,7 @@ where ))); }; let value = value.as_array().to_owned(); - let unit_into = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit_into = [L, M, T, I, N, THETA, J]; if unit_into == unit_from { Ok(Quantity(value, PhantomData)) } else { @@ -163,8 +194,16 @@ where } #[cfg(feature = "nalgebra")] -impl<'py, T: Integer, L: Integer, M: Integer, I: Integer, THETA: Integer, N: Integer, J: Integer> - FromPyObject<'_, 'py> for Quantity, SIUnit> +impl< + 'py, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, +> FromPyObject<'_, 'py> for Quantity, SIUnit> where Self: PrintUnit, { @@ -183,7 +222,7 @@ where ob.call_method0("__repr__")? ))); }; - let unit_into = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit_into = [L, M, T, I, N, THETA, J]; if unit_into == unit_from { Ok(Quantity(value, PhantomData)) } else { @@ -197,8 +236,16 @@ where } #[cfg(feature = "nalgebra")] -impl<'py, T: Integer, L: Integer, M: Integer, I: Integer, THETA: Integer, N: Integer, J: Integer> - FromPyObject<'_, 'py> for Quantity, SIUnit> +impl< + 'py, + const T: i8, + const L: i8, + const M: i8, + const I: i8, + const THETA: i8, + const N: i8, + const J: i8, +> FromPyObject<'_, 'py> for Quantity, SIUnit> where Self: PrintUnit, { @@ -217,7 +264,7 @@ where ob.call_method0("__repr__")? ))); }; - let unit_into = [L::I8, M::I8, T::I8, I::I8, N::I8, THETA::I8, J::I8]; + let unit_into = [L, M, T, I, N, THETA, J]; if unit_into == unit_from { Ok(Quantity(value, PhantomData)) } else { From 922e297481971eabdd7ebe55a9c7b0bb56ccbe52 Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Thu, 11 Dec 2025 16:40:38 +0100 Subject: [PATCH 2/8] increase range to -8..8 to accommodate weird units in feos --- src/lib.rs | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f740b84..e3d56e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,19 +181,23 @@ macro_rules! impl_add { }; } -impl_add!(-6; 0, 1, 2, 3, 4, 5, 6); -impl_add!(-5; -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(-4; -2, -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(-3; -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(-2; -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(-1; -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(0; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(1; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); -impl_add!(2; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4); -impl_add!(3; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3); -impl_add!(4; -6, -5, -4, -3, -2, -1, 0, 1, 2); -impl_add!(5; -6, -5, -4, -3, -2, -1, 0, 1); -impl_add!(6; -6, -5, -4, -3, -2, -1, 0); +impl_add!(-8; 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(-7; -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(-6; -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(-5; -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(-4; -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(-3; -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(-2; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(-1; -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(0; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(1; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7); +impl_add!(2; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(3; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); +impl_add!(4; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4); +impl_add!(5; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3); +impl_add!(6; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2); +impl_add!(7; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1); +impl_add!(8; -8, -7, -6, -5, -4, -3, -2, -1, 0); macro_rules! impl_neg { ($a:expr) => { @@ -214,7 +218,7 @@ macro_rules! impl_neg { }; } -impl_neg!(1, 2, 3, 4, 5, 6); +impl_neg!(1, 2, 3, 4, 5, 6, 7, 8); impl Sub> for Const where @@ -246,13 +250,15 @@ macro_rules! impl_mul { }; } +impl_mul!(-4; -2, 2); impl_mul!(-3; -2, 2); -impl_mul!(-2; -3, -2, 2, 3); -impl_mul!(-1; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); -impl_mul!(0; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); -impl_mul!(1; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); -impl_mul!(2; -3, -2, 2, 3); +impl_mul!(-2; -4, -3, -2, 2, 3, 4); +impl_mul!(-1; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); +impl_mul!(0; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); +impl_mul!(1; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); +impl_mul!(2; -4, -3, -2, 2, 3, 4); impl_mul!(3; -2, 2); +impl_mul!(4; -2, 2); macro_rules! impl_div { ($a:expr; $($b:expr),*) => { @@ -271,17 +277,19 @@ macro_rules! impl_div { }; } +impl_div!(-8; -8, -4, -2, 2, 4, 8); impl_div!(-6; -6, -3, -2, 2, 3, 6); impl_div!(-5; -5, 5); impl_div!(-4; -4, -2, 2, 4); impl_div!(-3; -3, 3); impl_div!(-2; -2, 2); -impl_div!(0; -6, -5, -4, -3, -2, 2, 3, 4, 5, 6); +impl_div!(0; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); impl_div!(2; -2, 2); impl_div!(3; -3, 3); impl_div!(4; -4, -2, 2, 4); impl_div!(5; -5, 5); impl_div!(6; -6, -3, -2, 2, 3, 6); +impl_div!(8; -8, -4, -2, 2, 4, 8); #[derive(Clone, Copy)] pub struct SIUnit< From f200f44be0aaa1e7592e8a0b78ae00ee7e3717c0 Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Thu, 11 Dec 2025 16:48:12 +0100 Subject: [PATCH 3/8] even more weird units --- src/lib.rs | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e3d56e3..a2cb5b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,23 +181,25 @@ macro_rules! impl_add { }; } -impl_add!(-8; 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(-7; -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(-6; -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(-5; -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(-4; -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(-3; -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(-2; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(-1; -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(0; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(1; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7); -impl_add!(2; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(3; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); -impl_add!(4; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4); -impl_add!(5; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3); -impl_add!(6; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2); -impl_add!(7; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1); -impl_add!(8; -8, -7, -6, -5, -4, -3, -2, -1, 0); +impl_add!(-9; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-8; -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-7; -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-6; -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-5; -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-4; -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-3; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-2; -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(-1; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(0; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_add!(1; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); +impl_add!(2; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7); +impl_add!(3; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); +impl_add!(4; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); +impl_add!(5; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4); +impl_add!(6; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3); +impl_add!(7; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2); +impl_add!(8; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1); +impl_add!(9; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0); macro_rules! impl_neg { ($a:expr) => { @@ -218,7 +220,7 @@ macro_rules! impl_neg { }; } -impl_neg!(1, 2, 3, 4, 5, 6, 7, 8); +impl_neg!(1, 2, 3, 4, 5, 6, 7, 8, 9); impl Sub> for Const where @@ -251,13 +253,13 @@ macro_rules! impl_mul { } impl_mul!(-4; -2, 2); -impl_mul!(-3; -2, 2); +impl_mul!(-3; -3, -2, 2, 3); impl_mul!(-2; -4, -3, -2, 2, 3, 4); -impl_mul!(-1; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); -impl_mul!(0; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); -impl_mul!(1; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); +impl_mul!(-1; -9, -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8, 9); +impl_mul!(0; -9, -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8, 9); +impl_mul!(1; -9, -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8, 9); impl_mul!(2; -4, -3, -2, 2, 3, 4); -impl_mul!(3; -2, 2); +impl_mul!(3; -3, -2, 2, 3); impl_mul!(4; -2, 2); macro_rules! impl_div { @@ -277,6 +279,7 @@ macro_rules! impl_div { }; } +impl_div!(-9; -9, -3, 3, 9); impl_div!(-8; -8, -4, -2, 2, 4, 8); impl_div!(-6; -6, -3, -2, 2, 3, 6); impl_div!(-5; -5, 5); @@ -290,6 +293,7 @@ impl_div!(4; -4, -2, 2, 4); impl_div!(5; -5, 5); impl_div!(6; -6, -3, -2, 2, 3, 6); impl_div!(8; -8, -4, -2, 2, 4, 8); +impl_div!(9; -9, -3, 3, 9); #[derive(Clone, Copy)] pub struct SIUnit< From 36fe00c79d3040f30814b20fbadafc79c1e26a6a Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Tue, 6 Jan 2026 13:40:58 +0100 Subject: [PATCH 4/8] clean up multiplications --- src/lib.rs | 58 +++++++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a2cb5b9..c105bf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,7 +139,6 @@ //! Interoperability with other crates can be achieved by activating the following features: #![doc = document_features::document_features!()] #![warn(clippy::all)] -#![expect(clippy::neg_multiply)] #[cfg(feature = "ndarray")] use ndarray::{Array, ArrayBase, Data, Dimension}; use std::marker::PhantomData; @@ -237,40 +236,25 @@ where macro_rules! impl_mul { ($a:expr; $($b:expr),*) => { + impl_mul!(0, $a, 0); $( - impl_mul!($a, $b); + impl_mul!($a, $b, {$a * $b}); + impl_mul!({-$a}, $b, {-{$a * $b}}); + impl_mul!($a, {-$b}, {-{$a * $b}}); + impl_mul!({-$a}, {-$b}, {$a * $b}); )* }; - ($a:expr, $b:expr) => { + ($a:expr, $b:expr, $c:expr) => { impl Mul> for Const<$a> { - type Output = Const<{ $a * $b }>; + type Output = Const<$c>; fn mul(self, _: Const<$b>) -> Self::Output { Const } } - }; -} -impl_mul!(-4; -2, 2); -impl_mul!(-3; -3, -2, 2, 3); -impl_mul!(-2; -4, -3, -2, 2, 3, 4); -impl_mul!(-1; -9, -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8, 9); -impl_mul!(0; -9, -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8, 9); -impl_mul!(1; -9, -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8, 9); -impl_mul!(2; -4, -3, -2, 2, 3, 4); -impl_mul!(3; -3, -2, 2, 3); -impl_mul!(4; -2, 2); - -macro_rules! impl_div { - ($a:expr; $($b:expr),*) => { - $( - impl_div!($a, $b); - )* - }; - ($a:expr, $b:expr) => { - impl Div> for Const<$a> { - type Output = Const<{ $a / $b }>; + impl Div> for Const<$c> { + type Output = Const<$a>; fn div(self, _: Const<$b>) -> Self::Output { Const @@ -279,21 +263,15 @@ macro_rules! impl_div { }; } -impl_div!(-9; -9, -3, 3, 9); -impl_div!(-8; -8, -4, -2, 2, 4, 8); -impl_div!(-6; -6, -3, -2, 2, 3, 6); -impl_div!(-5; -5, 5); -impl_div!(-4; -4, -2, 2, 4); -impl_div!(-3; -3, 3); -impl_div!(-2; -2, 2); -impl_div!(0; -8, -7, -6, -5, -4, -3, -2, 2, 3, 4, 5, 6, 7, 8); -impl_div!(2; -2, 2); -impl_div!(3; -3, 3); -impl_div!(4; -4, -2, 2, 4); -impl_div!(5; -5, 5); -impl_div!(6; -6, -3, -2, 2, 3, 6); -impl_div!(8; -8, -4, -2, 2, 4, 8); -impl_div!(9; -9, -3, 3, 9); +impl_mul!(1; 1, 2, 3, 4, 5, 6, 7, 8, 9); +impl_mul!(2; 1, 2, 3, 4); +impl_mul!(3; 1, 2, 3); +impl_mul!(4; 1, 2); +impl_mul!(5; 1); +impl_mul!(6; 1); +impl_mul!(7; 1); +impl_mul!(8; 1); +impl_mul!(9; 1); #[derive(Clone, Copy)] pub struct SIUnit< From 818cd45cb705ba7558ce76dbcfe5318c36bb6131 Mon Sep 17 00:00:00 2001 From: Gernot Bauer Date: Tue, 6 Jan 2026 16:54:22 +0100 Subject: [PATCH 5/8] Moved macros into build.rs, added Tests --- build.rs | 75 +++++++++++++++++++++++ src/lib.rs | 176 ++++++++++++++++++++--------------------------------- 2 files changed, 142 insertions(+), 109 deletions(-) create mode 100644 build.rs diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..012a684 --- /dev/null +++ b/build.rs @@ -0,0 +1,75 @@ +use std::env; +use std::fmt::Write; +use std::fs; +use std::path::Path; + +fn main() { + // Generate Neg, Add, Mul, Div, Sub impls for Const + // Limiting results of operations to values within [min, max] + + // range of exponents + // use i32 for results that would overflow i8, we will limit to min/max in loop + let min: i32 = -20; + let max: i32 = 20; + + let out_dir = env::var_os("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("const_impls.rs"); + let mut out = String::new(); + + // go over all exponent combinations + // for each operation, limit results to min/max + for a in min..=max { + // negation + let neg = -a; + if neg >= min && neg <= max { + writeln!( + &mut out, + "impl Neg for Const<{a}> {{ type Output = Const<{neg}>; fn neg(self) -> Self::Output {{ Const }} }}" + ).unwrap(); + } + + for b in min..=max { + // addition + let sum = a + b; + if sum >= min && sum <= max { + writeln!( + &mut out, + "impl Add> for Const<{a}> {{ type Output = Const<{sum}>; fn add(self, _: Const<{b}>) -> Self::Output {{ Const }} }}" + ).unwrap(); + } + + // subtraction + let diff = a - b; + if diff >= min && diff <= max { + writeln!( + &mut out, + "impl Sub> for Const<{a}> {{ type Output = Const<{diff}>; fn sub(self, _: Const<{b}>) -> Self::Output {{ Const }} }}" + ).unwrap(); + } + + // multiplication + let mul = a * b; + if mul >= min && mul <= max { + writeln!( + &mut out, + "impl Mul> for Const<{a}> {{ type Output = Const<{mul}>; fn mul(self, _: Const<{b}>) -> Self::Output {{ Const }} }}" + ).unwrap(); + } + + // division + // check: don't divide by 0 and only allow for integer results + if b != 0 && a % b == 0 { + let div = a / b; + if div >= min && div <= max { + writeln!( + &mut out, + "impl Div> for Const<{a}> {{ type Output = Const<{div}>; fn div(self, _: Const<{b}>) -> Self::Output {{ Const }} }}" + ).unwrap(); + } + } + } + } + + fs::write(&dest_path, out).unwrap(); + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/lib.rs b/src/lib.rs index c105bf9..4c7dd49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,115 +163,7 @@ type Quot = >::Output; pub struct Const; -macro_rules! impl_add { - ($a:expr; $($b:expr),*) => { - $( - impl_add!($a, $b); - )* - }; - ($a:expr, $b:expr) => { - impl Add> for Const<$a> { - type Output = Const<{ $a + $b }>; - - fn add(self, _: Const<$b>) -> Self::Output { - Const - } - } - }; -} - -impl_add!(-9; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-8; -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-7; -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-6; -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-5; -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-4; -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-3; -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-2; -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(-1; -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(0; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_add!(1; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8); -impl_add!(2; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7); -impl_add!(3; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6); -impl_add!(4; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); -impl_add!(5; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4); -impl_add!(6; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3); -impl_add!(7; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2); -impl_add!(8; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1); -impl_add!(9; -9, -8, -7, -6, -5, -4, -3, -2, -1, 0); - -macro_rules! impl_neg { - ($a:expr) => { - impl Neg for Const<$a> { - type Output = Const<{ -$a }>; - - fn neg(self) -> Self::Output { - Const - } - } - }; - ($($a:expr),+) => { - impl_neg!(0); - $( - impl_neg!($a); - impl_neg!({-$a}); - )+ - }; -} - -impl_neg!(1, 2, 3, 4, 5, 6, 7, 8, 9); - -impl Sub> for Const -where - Const: Neg, - Const: Add>, Output = Const>, - Const: Add, Output = Const>, -{ - type Output = Const; - - fn sub(self, _: Const) -> Self::Output { - Const - } -} - -macro_rules! impl_mul { - ($a:expr; $($b:expr),*) => { - impl_mul!(0, $a, 0); - $( - impl_mul!($a, $b, {$a * $b}); - impl_mul!({-$a}, $b, {-{$a * $b}}); - impl_mul!($a, {-$b}, {-{$a * $b}}); - impl_mul!({-$a}, {-$b}, {$a * $b}); - )* - }; - ($a:expr, $b:expr, $c:expr) => { - impl Mul> for Const<$a> { - type Output = Const<$c>; - - fn mul(self, _: Const<$b>) -> Self::Output { - Const - } - } - - impl Div> for Const<$c> { - type Output = Const<$a>; - - fn div(self, _: Const<$b>) -> Self::Output { - Const - } - } - }; -} - -impl_mul!(1; 1, 2, 3, 4, 5, 6, 7, 8, 9); -impl_mul!(2; 1, 2, 3, 4); -impl_mul!(3; 1, 2, 3); -impl_mul!(4; 1, 2); -impl_mul!(5; 1); -impl_mul!(6; 1); -impl_mul!(7; 1); -impl_mul!(8; 1); -impl_mul!(9; 1); +include!(concat!(env!("OUT_DIR"), "/const_impls.rs")); #[derive(Clone, Copy)] pub struct SIUnit< @@ -823,6 +715,72 @@ impl Deref for Dimensionless { mod test { use super::*; + #[test] + fn test_quantity_instantiation() { + let t = 10.0 * SECOND; + assert_eq!(t.0, 10.0); + + let l = 5.0 * METER; + assert_eq!(l.0, 5.0); + } + + #[test] + fn test_quantity_conversion() { + let dist = 1.5 * KILO * METER; + let raw_m = dist.convert_into(METER); + assert!((raw_m - 1500.0).abs() < 1e-10); + + let km = Quantity::new(1000.0); + let val_km = dist.convert_to(km); + assert!((val_km - 1.5).abs() < 1e-10); + } + + #[test] + fn test_celsius_conversion() { + let c = 0.0 * CELSIUS; + assert_eq!(c.0, 273.15); + + let zero = c / CELSIUS; + assert!(zero.abs() < 1e-15); + } + + #[test] + fn test_prefix_scaling() { + let v1 = 1.0 * MILLI * METER; + let v2 = 1.0 * KILO * METER; + + assert_eq!(v1.0, 0.001); + assert_eq!(v2.0, 1000.0); + } + + #[test] + fn test_quantity_arithmetic() { + let d = 10.0 * METER; + let t = 2.0 * SECOND; + + let v = d / t; + assert_eq!(v.0, 5.0); + + let m = 5.0 * KILOGRAM; + let a = 2.0 * METER / (SECOND * SECOND); + let f = m * a; + assert_eq!(f.0, 10.0); + + let l1 = 1.0 * METER; + let l2 = 2.0 * METER; + let l3 = l1 + l2; + assert_eq!(l3.0, 3.0); + } + + #[test] + fn test_angles() { + let ninety_deg = 90.0 * DEGREES; + let half_pi = std::f64::consts::FRAC_PI_2; + + assert!((ninety_deg.0 - half_pi).abs() < 1e-10); + assert!((ninety_deg.sin() - 1.0).abs() < 1e-10); + } + #[test] fn test_deref() { let pressure = 1.0135 * BAR; From d5a0ba91ece9de32d04552727911c11aec4ef618 Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Tue, 6 Jan 2026 17:20:46 +0100 Subject: [PATCH 6/8] add docstrings --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4c7dd49..78f03ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,10 +161,15 @@ type Negate = ::Output; type Prod = >::Output; type Quot = >::Output; +/// Convertion between const generics and the Rust type system. pub struct Const; +// implements all operations (+,-,*,/) for integers within a given range. include!(concat!(env!("OUT_DIR"), "/const_impls.rs")); +/// A compile-time representation of an SI unit based on the exponents of +/// the seven base units (time, length, mass, current, temperature, amount +/// of substance, luminous intensity) #[derive(Clone, Copy)] pub struct SIUnit< const T: i8, From f5208efaae59491089a02aa18385055694ebebab Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Tue, 6 Jan 2026 17:26:30 +0100 Subject: [PATCH 7/8] prepare release --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e722b3..b3c36cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.13.0] - 2026-01-06 +### Changed +- Use const generics instead of types from `typenum` to represent units. [#95](https://github.com/itt-ustutt/quantity/pull/95) + ## [0.12.2] - 2025-12-04 ### Fixed - Also updated `num-dual` dependency to 0.13 to fix incorrect dependency resolution for downstream crates. [#95](https://github.com/itt-ustutt/quantity/pull/95) diff --git a/Cargo.toml b/Cargo.toml index a50c0c5..f8dd49e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quantity" -version = "0.12.2" +version = "0.13.0" authors = [ "Philipp Rehner ", "Gernot Bauer ", diff --git a/README.md b/README.md index 7b9d91a..7d9469b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Add this to your `Cargo.toml`: ``` [dependencies] -quantity = "0.12" +quantity = "0.13" ``` ## Examples From fdcfbce84eb45435368fd1908db35daaea6acb3a Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Tue, 6 Jan 2026 17:28:01 +0100 Subject: [PATCH 8/8] fix README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7d9469b..ca9efe9 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Calculate pressure of an ideal gas. ```rust let temperature = 25.0 * CELSIUS; -let volume = 1.5 * METER.powi::(); +let volume = 1.5 * METER.powi::<3>(); let moles = 75.0 * MOL; let pressure = moles * RGAS * temperature / volume; println!("{:.5}", pressure); // 123.94785 kPa @@ -36,7 +36,7 @@ Calculate the gravitational pull of the moon on the earth. let mass_earth = 5.9724e24 * KILOGRAM; let mass_moon = 7.346e22 * KILOGRAM; let distance = 383.398 * KILO * METER; -let force = G * mass_earth * mass_moon / distance.powi::(); +let force = G * mass_earth * mass_moon / distance.powi::<2>(); println!("{:.5e}", force); // 1.99208e26 N ``` @@ -44,7 +44,7 @@ Calculate the pressure distribution in the atmosphere using the barometric formu ```rust let z = Quantity::linspace(1.0 * METER, 70.0 * KILO * METER, 10); -let g = 9.81 * METER / SECOND.powi::(); +let g = 9.81 * METER / SECOND.powi::<2>(); let m = 28.949 * GRAM / MOL; let t = 10.0 * CELSIUS; let p0 = BAR;