Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit ergonomics #73

Merged
merged 40 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
cb3a049
add Magnitude type (that is - for now - just a wrapper over f64) and …
Tehforsch Jan 14, 2024
78f9af3
set up magnitude faulty float multiplication
Tehforsch Jan 15, 2024
ac482eb
generate unit code
Tehforsch Jan 16, 2024
71ff80e
use mantissa/exponent rep
Tehforsch Jan 21, 2024
38c25fb
Impl Mul / Div for Magnitude/f64
Tehforsch Jan 21, 2024
861f6ab
move dimensions inside of module
Tehforsch Jan 21, 2024
7669d09
generate only generic dimensions
Tehforsch Jan 21, 2024
5983621
generate constants
Tehforsch Jan 21, 2024
5c91277
fix spans
Tehforsch Jan 21, 2024
37aed11
add magnitude f32 mul impl
Tehforsch Jan 21, 2024
7b88b5b
revive float tests
Tehforsch Jan 22, 2024
ce8f6b4
revive type aliases test
Tehforsch Jan 22, 2024
9b849bc
fix unit aliases / type aliases test
Tehforsch Jan 22, 2024
6c8ee33
revive debug tests
Tehforsch Jan 22, 2024
f09ef38
revive dimension defs tests
Tehforsch Jan 22, 2024
645a3e6
revive gas test
Tehforsch Jan 22, 2024
a625fbb
revive glam tests
Tehforsch Jan 22, 2024
b56c8d2
revive mpi tests
Tehforsch Jan 22, 2024
76034b5
revive serde tests
Tehforsch Jan 22, 2024
e3d21c7
revive rand tests
Tehforsch Jan 22, 2024
19c7086
revive rational dimension tests
Tehforsch Jan 22, 2024
3746e69
revive compile_fail tests
Tehforsch Jan 22, 2024
1710656
update doctests and readme
Tehforsch Jan 22, 2024
f58f049
fix serde doctest
Tehforsch Jan 22, 2024
3cf36b4
mpi annotate
Tehforsch Jan 22, 2024
eca16f4
update doc
Tehforsch Feb 25, 2024
9a6ed4d
update readme
Tehforsch Feb 25, 2024
23724e1
add example for dimensionless add
Tehforsch Feb 25, 2024
7452d0e
add doc for .value, Deref and .value_unchecked()
Tehforsch Feb 25, 2024
5ab310f
document debug, powi/sqrt/cbrt/powf
Tehforsch Feb 25, 2024
d3a17b7
add doc on value_unchecked and creation
Tehforsch Feb 25, 2024
5951a3c
add doc on value_in
Tehforsch Feb 25, 2024
85e4eb1
add RuntimeUnit to allow multiplication / division of units
Tehforsch Feb 25, 2024
b474fe0
take both Unit and RuntimeUnit in value_in
Tehforsch Feb 25, 2024
07a1f0d
minor fixes in readme
Tehforsch Feb 25, 2024
011fbb5
add links to crates
Tehforsch Feb 25, 2024
9546634
fix warnings in new rust version
Tehforsch Feb 25, 2024
6f27a78
remove allow attrs that were needed due to a previous clippy bug
Tehforsch Feb 25, 2024
a6da0c1
remove some unused type annotations
Tehforsch Feb 25, 2024
a8e3043
minor formatting tweaks
Tehforsch Feb 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
300 changes: 188 additions & 112 deletions README.md

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions crates/diman_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,3 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/tehforsch/diman"

[dependencies]

[dev-dependencies]
num-traits = { version = "0.2.17", default-features = false }
10 changes: 6 additions & 4 deletions crates/diman_lib/src/dimension_exponent.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::ops::{AddAssign, Mul, Neg};
use core::ops::{AddAssign, Mul, Neg};

use crate::magnitude::Magnitude;

pub trait DimensionExponent: Clone + PartialEq + Copy + Mul + AddAssign + Neg {
fn float_pow(num: f64, exponent: Self) -> f64;
fn float_pow(mag: Magnitude, exponent: Self) -> Magnitude;
fn one() -> Self;
fn zero() -> Self;
fn from_int(i: i32) -> Self;
Expand All @@ -16,8 +18,8 @@ impl DimensionExponent for i64 {
0
}

fn float_pow(num: f64, exponent: Self) -> f64 {
num.powi(exponent as i32)
fn float_pow(num: Magnitude, exponent: Self) -> Magnitude {
Magnitude::from_f64(num.into_f64().powi(exponent as i32))
}

fn from_int(i: i32) -> Self {
Expand Down
1 change: 1 addition & 0 deletions crates/diman_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
#![feature(generic_const_exprs, adt_const_params)]

pub mod dimension_exponent;
pub mod magnitude;
pub mod ratio;
pub mod runtime_unit_storage;
161 changes: 161 additions & 0 deletions crates/diman_lib/src/magnitude.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use core::{
marker::ConstParamTy,
ops::{Div, Mul},
};

pub const MAX_NUM_FACTORS: usize = 10;

#[derive(Clone, Copy, PartialEq, Eq, ConstParamTy, Debug)]
struct Factor {
f: u64,
exp: i16,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, ConstParamTy)]
pub struct Magnitude {
pub mantissa: u64,
pub exponent: i16,
pub sign: i8,
}

// From num-traits
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
let bits: u64 = f.to_bits();
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
let mantissa = if exponent == 0 {
(bits & 0xfffffffffffff) << 1
} else {
(bits & 0xfffffffffffff) | 0x10000000000000
};
// Exponent bias + mantissa shift
exponent -= 1023 + 52;
(mantissa, exponent, sign)
}

impl Magnitude {
pub fn from_f64(f: f64) -> Self {
let (mantissa, exponent, sign) = integer_decode_f64(f);
Self {
mantissa,
exponent,
sign,
}
}

pub fn into_f64(self) -> f64 {
self.sign as f64 * self.mantissa as f64 * 2.0f64.powi(self.exponent as i32)
}

pub fn into_f32(self) -> f32 {
self.into_f64() as f32
}

pub fn pow_rational(&self, num: i64, denom: i64) -> Magnitude {
Self::from_f64(self.into_f64().powf(num as f64 / denom as f64))
}

pub fn is_one(&self) -> bool {
self.into_f64() == 1.0
}
}

impl Mul<Magnitude> for Magnitude {
type Output = Self;

fn mul(self, rhs: Magnitude) -> Self::Output {
Self::from_f64(self.into_f64() * rhs.into_f64())
}
}

impl Div<Magnitude> for Magnitude {
type Output = Self;

fn div(self, rhs: Magnitude) -> Self::Output {
Self::from_f64(self.into_f64() / rhs.into_f64())
}
}

impl Mul<f64> for Magnitude {
type Output = Self;

fn mul(self, rhs: f64) -> Self::Output {
Self::from_f64(self.into_f64() * rhs)
}
}

impl Div<f64> for Magnitude {
type Output = Self;

fn div(self, rhs: f64) -> Self::Output {
Self::from_f64(self.into_f64() / rhs)
}
}

impl Mul<Magnitude> for f64 {
type Output = Self;

fn mul(self, rhs: Magnitude) -> Self::Output {
self * rhs.into_f64()
}
}

impl Div<Magnitude> for f64 {
type Output = Self;

fn div(self, rhs: Magnitude) -> Self::Output {
self / rhs.into_f64()
}
}

impl Mul<f32> for Magnitude {
type Output = Self;

fn mul(self, rhs: f32) -> Self::Output {
Self::from_f64((self.into_f32() * rhs) as f64)
}
}

impl Div<f32> for Magnitude {
type Output = Self;

fn div(self, rhs: f32) -> Self::Output {
Self::from_f64((self.into_f32() / rhs) as f64)
}
}

impl Mul<Magnitude> for f32 {
type Output = Self;

fn mul(self, rhs: Magnitude) -> Self::Output {
self * rhs.into_f32()
}
}

impl Div<Magnitude> for f32 {
type Output = Self;

fn div(self, rhs: Magnitude) -> Self::Output {
self / rhs.into_f32()
}
}

#[cfg(test)]
mod tests {
use crate::magnitude::Magnitude;

#[test]
fn magnitude_as_f64_round_trip() {
let check_equality = |x: f64| {
assert_eq!(Magnitude::from_f64(x).into_f64(), x);
};
for x in 0..10000 {
let x = (x as f64) * 0.01;
check_equality(x);
}
for exp in -50..50 {
let x = 2.0f64.powi(exp);
check_equality(x);
}
}
}
6 changes: 3 additions & 3 deletions crates/diman_lib/src/ratio.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::dimension_exponent::DimensionExponent;
use crate::{dimension_exponent::DimensionExponent, magnitude::Magnitude};

#[derive(
::core::cmp::PartialEq,
Expand Down Expand Up @@ -93,8 +93,8 @@ impl DimensionExponent for Ratio {
Self { num: 0, denom: 1 }
}

fn float_pow(num: f64, exponent: Self) -> f64 {
num.powf(exponent.num as f64 / exponent.denom as f64)
fn float_pow(num: Magnitude, exponent: Self) -> Magnitude {
num.pow_rational(exponent.num, exponent.denom)
}

fn from_int(i: i32) -> Self {
Expand Down
13 changes: 9 additions & 4 deletions crates/diman_unit_system/src/codegen/debug_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Codegen {
let units: TokenStream = units
.filter_map(|unit| {
let dim = self.get_dimension_expr(&unit.dimensions);
let magnitude = unit.magnitude;
let magnitude = unit.magnitude.into_f64();
let symbol = &unit.symbol.as_ref()?.0.to_string();
Some(quote! {
#runtime_unit::new(
Expand All @@ -35,17 +35,22 @@ impl Codegen {
})
})
.collect();
let dimension_type = &self.defs.dimension_type;
quote! {
let units_array = &[#units];
let units_array: &[#runtime_unit::<#dimension_type>] = &[#units];
let units = #runtime_unit_storage::new(units_array);
}
}

pub fn gen_debug_trait_impl(&self) -> TokenStream {
let dimension_type = &self.defs.dimension_type;
let quantity_type = &self.defs.quantity_type;
let units_storage =
self.runtime_unit_storage(self.defs.units.iter().filter(|unit| unit.magnitude == 1.0));
let units_storage = self.runtime_unit_storage(
self.defs
.units
.iter()
.filter(|unit| unit.magnitude.is_one()),
);
let get_base_dimension_symbols = self
.defs
.base_dimensions
Expand Down
Loading