iliekturtles / uom Goto Github PK
View Code? Open in Web Editor NEWUnits of measurement -- type-safe zero-cost dimensional analysis
License: Apache License 2.0
Units of measurement -- type-safe zero-cost dimensional analysis
License: Apache License 2.0
Document all methods and their parameters.
https://doc.rust-lang.org/core/fmt/trait.Debug.html
Quantity
$quantities
(Dimension)BaseUnits
$unit
(Measurement units)While I was working on an unrelated PR, I got this error during a test run:
---- tests::quantities_macro::fractional::f32::rem stdout ----
thread 'tests::quantities_macro::fractional::f32::rem' panicked at '[quickcheck] TEST FAILED. Arguments: (A { v: 99.59967 }, A { v: 16.073349 })', C:\Users\radix\.cargo\registry\src\github.com-1ecc6299db9ec823\quickcheck-0.5.0\src\tester.rs:171:27
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
tests::quantities_macro::fractional::f32::rem
test result: FAILED. 147 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
Add area quantity and associated units.
I haven't had a chance to dig into this yet but I noticed a crash when trying to create reasonably large u64
Lengths.
This is some example code that fails at runtime when creating the Length quantity:
#[macro_use]
extern crate uom;
use uom::si::length::{centimeter, meter};
use uom::si;
mod u64units {
ISQ!(
uom::si,
u64,
(centimeter, gram, second, ampere, kelvin, mole, candela)
);
}
fn main() {
let max_u64 = u64::max_value();
u64units::Length::new::<centimeter>(max_u64 / 16 + 1);
}
Here's my traceback:
thread 'main' panicked at 'attempt to multiply with overflow', C:\projects\rust\src\libcore\ops\arith.rs:309:45
9: core::ops::arith::{{impl}}::mul
at C:\projects\rust\src\libcore\ops\arith.rs:309
10: num_rational::{{impl}}::div<u64>
at ...\num-rational-0.1.40\src\lib.rs:442
11: num_rational::{{impl}}::div<u64>
at ...\num-rational-0.1.40\src\lib.rs:375
12: uom::si::Quantity<Dimension, Units<u64>, u64>::new<Units<u64>,u64,uom::si::length::centimeter>
at ...\uom-570397b139e674d8\595b3ae\src\quantity.rs:227
13: uomtest::main
at .\src\bin\uomtest.rs:39
14: panic_unwind::__rust_maybe_catch_panic
at C:\projects\rust\src\libpanic_unwind\lib.rs:99
15: std::rt::lang_start
at C:\projects\rust\src\libstd\rt.rs:52
16: main
Using max_u64 / 16
instead of max_u64 / 16 + 1
works. This also seems to only happen when using lengths with a base unit smaller than meter
-- if I use meter
as my base unit I can create quantities up to u64::max_value()
.
See https://github.com/blog/1184-contributing-guidelines and https://help.github.com/articles/setting-guidelines-for-repository-contributors/ for documentation and some examples.
Add conversion calculations to support thermodynamic temperature units. This requires #78.
Add additional time units.
Add constant
? Add const fn
? impl Zero
?
Add force quantity and associated units.
The short version: comparing integral quantities with Eq can be many orders of magnitude slower than regular comparison. This is magnified for the bigger types, with i64 being about a few thousand times slower than comparing plain i64 values. I assume the same happens for the PartialOrd
implementation.
Running `C:\Users\radix\Projects\pandt\target\release\deps\uom_ops-6068a9413eff2c40.exe --bench`
simple u32 time: [376.27 ps 383.53 ps 390.64 ps]
Found 4 outliers among 100 measurements (4.00%)
3 (3.00%) high mild
1 (1.00%) high severe
simple i64 time: [366.59 ps 369.57 ps 372.66 ps]
Found 8 outliers among 100 measurements (8.00%)
2 (2.00%) low mild
3 (3.00%) high mild
3 (3.00%) high severe
uom u32 time: [808.11 ns 814.27 ns 821.16 ns]
Found 9 outliers among 100 measurements (9.00%)
3 (3.00%) low mild
2 (2.00%) high mild
4 (4.00%) high severe
uom i64 time: [1.5856 us 1.5981 us 1.6113 us]
Found 13 outliers among 100 measurements (13.00%)
1 (1.00%) low severe
4 (4.00%) low mild
4 (4.00%) high mild
4 (4.00%) high severe
Here's the benchmark:
#[macro_use] extern crate criterion;
extern crate uom;
extern crate pandt;
use uom::si::length::centimeter;
use criterion::Criterion;
use pandt::types::{u32units, i64units};
fn simple_eq_u32(n: u32, n2: u32) -> bool { n == n2 }
fn simple_eq_i64(n: u64, n2: u64) -> bool { n == n2 }
fn uom_eq_u32(n: u32units::Length, n2: u32units::Length) -> bool { n == n2 }
fn uom_eq_i64(n: i64units::Length, n2: i64units::Length) -> bool { n == n2 }
fn simple_benchmark(c: &mut Criterion) {
c.bench_function("simple u32", |b| b.iter(|| simple_eq_u32(100, 200)));
c.bench_function("simple i64", |b| b.iter(|| simple_eq_i64(100, 200)));
}
fn uom_benchmark(c: &mut Criterion) {
let u32n = u32units::Length::new::<centimeter>(100);
let u32n2 = u32units::Length::new::<centimeter>(200);
let i64n = i64units::Length::new::<centimeter>(100);
let i64n2 = i64units::Length::new::<centimeter>(200);
c.bench_function("uom u32", |b| b.iter(|| uom_eq_u32(u32n, u32n2)));
c.bench_function("uom i64", |b| b.iter(|| uom_eq_i64(i64n, i64n2)));
}
criterion_group!(benches, simple_benchmark, uom_benchmark);
criterion_main!(benches);
By my reading of the code, this stems from the fact that Quantities that aren't from the same ISQ!
are compatible with each other -- but at the cost of having to perform a conversion, apparently using num-rational
. This is something I would be happy to forego - if uom's Eq implementation had a Rhs = Self
, it could just perform a simple comparison. Perhaps a flag to the ISQ!
macro could turn off this conversion generation and only support comparison of identical types?
Add support controlled by a serde
feature. Enable or disable by default?
Add additional length units.
impl Op<Quantity<...>> for Quantity<..>
is already complete. Add the following reference implementations:
impl<'a, 'b> Op<&'a Quantity<...>> for &'b Quantity<..>
impl<'a> Op<&'a Quantity<...>> for Quantity<..>
impl<'a> Op<Quantity<...>> for &'a Quantity<..>
I didn't realize that I didn't have integers enabled when running tests until I tried to write integer-specific tests for the new Saturating support I'm working on. When I tried to run them, I got these failures (with master, with u32 enabled):
si::acceleration::tests::u32::check_units
si::area::tests::u32::check_units
si::force::tests::u32::check_units
si::frequency::tests::u32::check_units
si::velocity::test::u32::check_units
si::volume::tests::u32::check_units
tests::system_macro::op_assign::u32::sub_assign
tests::system_macro::u32::sub
It seems that travis isn't running tests with ints enabled either.
rem_assign arguments -99.32110293556526 and 4.277491538217234
---- tests::quantities_macro::float::f64::rem_assign stdout ----
thread 'tests::quantities_macro::float::f64::rem_assign' panicked at '[quickcheck] TEST FAILED. Arguments: (A { v: -99.32110293556526 }, A { v: 4.277491538217234 })', C:\Users\appveyor\.cargo\registry\src\github.com-1ecc6299db9ec823\quickcheck-0.5.0\src\tester.rs:171:27
note: Run with `RUST_BACKTRACE=1` for a backtrace.
Add frequency quantity and associated units.
e.g.
quantity: Length; "length";
...
@meter: prefix!(none); "m"; "meter";
@millimeter: prefix!(milli); "mm"; "millimeter";
Dimension
$quantity<U, V>
new
get
Unit<V>
$unit
super::Conversion<$V>
description
https://doc.rust-lang.org/std/primitive.f32.html
is_nan
is_infinite
is_finite
is_normal
classify
floor
-- by unitceil
-- by unitround
-- by unittrunc
-- by unitfract
-- by unitabs
signum
is_sign_positive
is_sign_negative
mul_add
recip
-- returns quantity of different dimensionspowi
-- returns quantity of different dimensionssqrt
-- returns quantity of different dimensionsexp
exp2
ln
log
log2
log10
max
min
cbrt
-- returns quantity of different dimensionshypot
-- Only for Length
?Add support for integral types (i8, u8, i16, u16, i32, u32, i64, u64, usize? isize?, i128, u128) as the underlying storage type so that users can create new systems which do not use a floating point type. Use features to control code generation. Not all methods may be applicable. Types shouldn't be implemented for the ISQ.
Document all generic parameters such as D
on Quantity<D, U, V>
.
Quantity<D, U, V>
Add
AddAssign
Sub
SubAssign
Mul
MulAssign
Div
DivAssign
Neg
Rem
RemAssign
Dimension
Units<D, V>
conversion
Unit
Conversion<V>
$quantities<$symbol>
Add
Sub
One
Debug
fmt
BaseUnits
Add
Sub
Units
$quantities!
Create constructor method for unnamed quantities:
/// https://en.wikipedia.org/wiki/Gravitational_constant
let G = Quantity::<ISQ<P3, N1, N2, Z0, Z0, Z0, Z0>, SI<f64>, f64>::new(6.674e-11);
Add acceleration quantity and associated units.
Handle overflows in conversion factors so that factors that exceed the underlying storage type's min/max values do not cause errors. Currently tests are failing because conversion factors overflow the underlying storage type.
Conversion
for types that can't represent the conversion factor? e.g. don't implement Conversion
for kilometer
when the underlying storage type is u8
.Conversion
but have tests skip factors that can't accurately be represented?Add volume quantity and associated units.
Add additional velocity units.
https://doc.rust-lang.org/core/fmt/trait.Binary.html
https://doc.rust-lang.org/core/fmt/trait.Display.html
https://doc.rust-lang.org/core/fmt/trait.LowerExp.html
https://doc.rust-lang.org/core/fmt/trait.LowerHex.html
https://doc.rust-lang.org/core/fmt/trait.Octal.html
https://doc.rust-lang.org/core/fmt/trait.UpperExp.html
https://doc.rust-lang.org/core/fmt/trait.UpperHex.html
Is there a way to use the fmt syntax or flags to include an implicit unit conversion, unit abbreviation, or unit label?
// What replaces `...` to allow the following outputs: 10 m, 10 meters, 32.8084 ft, 32.8084 feet
println!("{...}", new Length(10, meter));
Quantity
$quantities
(Dimension)BaseUnits
$unit
(Measurement units)Compiling uom
with all features enabled takes a significant amount of time. -Ztime-passes
shows that the issue is in privacy checking:
$ RUSTFLAGS="-Ztime-passes" cargo +nightly test --no-run
...
time: 172.929; rss: 507MB privacy checking
...
Timing for this pass increases linearly with the number of underlying storage types enabled. Enabling features for underlying storage types adds impl
blocks and type aliases for existing types. No new types are added. Additionally, all struct
s and trait
s are pub
in uom
.
The graph below shows compile times, as reported by cargo
for test --no-run
in blue and build
in red:
Test | Build | Features |
---|---|---|
15.74 | 5.5 | f64 |
20.4 | 5.43 | f32,f64 |
38.84 | 6.24 | bigrational,f32,f64 |
37.75 | 7.4 | rational64,bigrational,f32,f64 |
48.28 | 8.26 | rational32,rational64,bigrational,f32,f64 |
55.52 | 9.26 | rational,rational32,rational64,bigrational,f32,f64 |
67.57 | 10.89 | biguint,rational,rational32,rational64,bigrational,f32,f64 |
96.81 | 12.5 | bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
94.53 | 15.21 | i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
106.92 | 16.4 | i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
116.34 | 18.17 | i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
131.29 | 20.2 | i8,i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
144.3 | 22.19 | isize,i8,i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
137.48 | 24.67 | u64,isize,i8,i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
158.4 | 26.93 | u32,u64,isize,i8,i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
194.9 | 29.69 | u16,u32,u64,isize,i8,i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
211.47 | 33.53 | u8,u16,u32,u64,isize,i8,i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
198.5 | 36.63 | usize,u8,u16,u32,u64,isize,i8,i16,i32,i64,bigint,biguint,rational,rational32,rational64,bigrational,f32,f64 |
My application which uses uom doesn't need additional num-*
crates. Given that num has optional dependencies which are enabled by default, I tried setting default-features = false
in my Cargo.toml, but the default features were still enabled. I eventually figured out that this is because uom
is depending on num
without specifying default-features = false
.
Would support for 'bytes' be within scope for this library? Would that work out well with using f32 / f64 storage? It seems like perhaps using u64
for bytes, but floating point for all larger units might be useful?
This might just be me being new to rust, but I'm having a really tough time cross compiling uom for ARM. Starting from a lib crate that builds fine, if I add
[dependencies.uom]
default-features = false
features = [ "si", "usize" ]
version = "*"
to Cargo.toml and then run xargo build
it tells me
error[E0463]: can't find crate for `std`
|
= note: the `thumbv7em-none-eabihf` target may not be installed
error: aborting due to previous error
error: Could not compile `num-traits`.
Caused by:
process didn't exit successfully: `rustc --crate-name num_traits ~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.0/src/lib.rs --crate-type lib --emit=dep-info,link -C codegen-units=1 -C debuginfo=2 --cfg feature="default" --cfg feature="std" -C metadata=459f1b7f38ae1057 -C extra-filename=-459f1b7f38ae1057 --out-dir target/thumbv7em-none-eabihf/debug/deps --target thumbv7em-none-eabihf -L dependency=target/thumbv7em-none-eabihf/debug/deps -L dependency=target/debug/deps --cap-lints allow -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld -Z thinlto=no --sysroot ~/.xargo` (exit code: 101)
of special note there is the part that says --cfg feature="std"
. It seems that specifying no_std
for uom
isn't enforcing that constraint on upstream dependencies.
https://doc.rust-lang.org/core/str/trait.FromStr.html
Quantity
$unit
(Measurement units)https://travis-ci.org/iliekturtles/uom/jobs/217533536
Remove cargo-update
from build scripts as it appears to no longer support 1.15.0.
Allow one location? Both?
Constant created by system macro (e.g. ISQ!
) with the appropriate unit. Accessed in a submodule so there are no name collisions? let _ = uom::si::f32::velocity::c;
quantity! {
quantity: Velocity; "velocity";
dimension: ...;
units { ... }
constants {
c: 299_792_458 meter_per_second,
}
}
Constant created by system macro (e.g. ISQ!
) with appropriate base units. let _ = uom::si::f32::G;
system! {
quantities: ISQ {
length: meter, L;
...
}
units: SI { ... }
constants:{
G: 6.674_083_1_E-11 ISQ<P3, N1, N2, Z0, Z0, Z0, Z0>,
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.