Skip to content

Commit

Permalink
Merge pull request #73 from Tehforsch/unit-ergonomics
Browse files Browse the repository at this point in the history
Unit ergonomics
  • Loading branch information
Tehforsch authored Feb 25, 2024
2 parents 3e92f40 + a8e3043 commit d962a26
Show file tree
Hide file tree
Showing 56 changed files with 1,791 additions and 931 deletions.
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

0 comments on commit d962a26

Please sign in to comment.