Skip to content

Commit

Permalink
Implement floating point fractional methods.
Browse files Browse the repository at this point in the history
`floor`, `ceil`, `round`, `trunc`, and `fract`. Part of #11
  • Loading branch information
iliekturtles committed Jun 12, 2017
1 parent 42173bc commit feb2450
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 2 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
## [Unreleased]

### Added
* [#11](https://github.com/iliekturtles/uom/issues/11) Floating point classification methods
`classify`, `is_finite`, `is_infinte`, `is_nan`, and `is_normal` implemented for `Quantity`.
* [#11](https://github.com/iliekturtles/uom/issues/11) Add floating point classification methods
`classify`, `is_finite`, `is_infinte`, `is_nan`, and `is_normal` for `Quantity`.
* [#11](https://github.com/iliekturtles/uom/issues/11) Add floating point fractional methods
`floor`, `ceil`, `round`, `trunc`, and `fract` for `Quantity`.

## [v0.14.0] — 2017-05-30

Expand Down
48 changes: 48 additions & 0 deletions src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,54 @@ macro_rules! quantity {
self.value * <U as super::Units<Dimension, $V>>::conversion()
/ <N as super::Conversion<$V>>::conversion()
}

/// Returns the largest integer less than or equal to a number in the given
/// measurement unit.
#[cfg(feature = "std")]
#[inline(always)]
pub fn floor<N>(self, _unit: N) -> Self
where N: Unit<$V>,
{
Self::new::<N>(self.get(_unit).floor())
}

/// Returns the smallest integer less than or equal to a number in the given
/// measurement unit.
#[cfg(feature = "std")]
#[inline(always)]
pub fn ceil<N>(self, _unit: N) -> Self
where N: Unit<$V>,
{
Self::new::<N>(self.get(_unit).ceil())
}

/// Returns the nearest integer to a number in the in given measurement unit.
/// Round half-way cases away from 0.0.
#[cfg(feature = "std")]
#[inline(always)]
pub fn round<N>(self, _unit: N) -> Self
where N: Unit<$V>,
{
Self::new::<N>(self.get(_unit).round())
}

/// Returns the integer part of a number in the given measurement unit.
#[cfg(feature = "std")]
#[inline(always)]
pub fn trunc<N>(self, _unit: N) -> Self
where N: Unit<$V>,
{
Self::new::<N>(self.get(_unit).trunc())
}

/// Returns the fractional part of a number in the given measurement unit.
#[cfg(feature = "std")]
#[inline(always)]
pub fn fract<N>(self, _unit: N) -> Self
where N: Unit<$V>,
{
Self::new::<N>(self.get(_unit).fract())
}
}

$(impl Unit<$V> for $unit {}
Expand Down
220 changes: 220 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,116 @@ macro_rules! test {
assert_eq!(1.0, m1.get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn floor() {
let l1 = TLength::new::<kilometer>(3.9999);
let l2 = TLength::new::<kilometer>(3.0001);
let l3 = TLength::new::<meter>(3.9999);
let l4 = TLength::new::<meter>(3.0001);
let m1 = TMass::new::<kilogram>(3.9999);
let m2 = TMass::new::<kilogram>(3.0001);

assert_eq!(3.0, l1.floor(kilometer).get(kilometer));
assert_eq!(3999.0, l1.floor(meter).get(meter));
assert_eq!(3.0, l2.floor(kilometer).get(kilometer));
assert_eq!(3000.0, l2.floor(meter).get(meter));
assert_eq!(0.0, l3.floor(kilometer).get(kilometer));
assert_eq!(3.0, l3.floor(meter).get(meter));
assert_eq!(0.0, l4.floor(kilometer).get(kilometer));
assert_eq!(3.0, l4.floor(meter).get(meter));
assert_eq!(3.0, m1.floor(kilogram).get(kilogram));
assert_eq!(3.0, m2.floor(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn ceil() {
let l1 = TLength::new::<kilometer>(3.9999);
let l2 = TLength::new::<kilometer>(3.0001);
let l3 = TLength::new::<meter>(3.9999);
let l4 = TLength::new::<meter>(3.0001);
let m1 = TMass::new::<kilogram>(3.9999);
let m2 = TMass::new::<kilogram>(3.0001);

assert_eq!(4.0, l1.ceil(kilometer).get(kilometer));
assert_eq!(4000.0, l1.ceil(meter).get(meter));
assert_eq!(4.0, l2.ceil(kilometer).get(kilometer));
assert_eq!(3001.0, l2.ceil(meter).get(meter));
assert_eq!(1.0, l3.ceil(kilometer).get(kilometer));
assert_eq!(4.0, l3.ceil(meter).get(meter));
assert_eq!(1.0, l4.ceil(kilometer).get(kilometer));
assert_eq!(4.0, l4.ceil(meter).get(meter));
assert_eq!(4.0, m1.ceil(kilogram).get(kilogram));
assert_eq!(4.0, m2.ceil(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn round() {
let l1 = TLength::new::<kilometer>(3.3);
let l2 = TLength::new::<kilometer>(3.5);
let l3 = TLength::new::<meter>(3.3);
let l4 = TLength::new::<meter>(3.5);
let m1 = TMass::new::<kilogram>(3.3);
let m2 = TMass::new::<kilogram>(3.5);

assert_eq!(3.0, l1.round(kilometer).get(kilometer));
assert_eq!(3300.0, l1.round(meter).get(meter));
assert_eq!(4.0, l2.round(kilometer).get(kilometer));
assert_eq!(3500.0, l2.round(meter).get(meter));
assert_eq!(0.0, l3.round(kilometer).get(kilometer));
assert_eq!(3.0, l3.round(meter).get(meter));
assert_eq!(0.0, l4.round(kilometer).get(kilometer));
assert_eq!(4.0, l4.round(meter).get(meter));
assert_eq!(3.0, m1.round(kilogram).get(kilogram));
assert_eq!(4.0, m2.round(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn trunc() {
let l1 = TLength::new::<kilometer>(3.3);
let l2 = TLength::new::<kilometer>(3.5);
let l3 = TLength::new::<meter>(3.3);
let l4 = TLength::new::<meter>(3.5);
let m1 = TMass::new::<kilogram>(3.3);
let m2 = TMass::new::<kilogram>(3.5);

assert_eq!(3.0, l1.trunc(kilometer).get(kilometer));
assert_eq!(3300.0, l1.trunc(meter).get(meter));
assert_eq!(3.0, l2.trunc(kilometer).get(kilometer));
assert_eq!(3500.0, l2.trunc(meter).get(meter));
assert_eq!(0.0, l3.trunc(kilometer).get(kilometer));
assert_eq!(3.0, l3.trunc(meter).get(meter));
assert_eq!(0.0, l4.trunc(kilometer).get(kilometer));
assert_eq!(3.0, l4.trunc(meter).get(meter));
assert_eq!(3.0, m1.trunc(kilogram).get(kilogram));
assert_eq!(3.0, m2.trunc(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn fract() {
let l1 = TLength::new::<kilometer>(3.3);
let l2 = TLength::new::<kilometer>(3.5);
let l3 = TLength::new::<meter>(3.3);
let l4 = TLength::new::<meter>(3.5);
let m1 = TMass::new::<kilogram>(3.3);
let m2 = TMass::new::<kilogram>(3.5);

ulps_eq!(0.3, l1.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.0, l1.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.0, l2.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.5, l2.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.0033, l3.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.3, l3.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.00035, l4.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.5, l4.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.3, m1.fract(kilogram).get(kilogram), epsilon = EPSILON);
ulps_eq!(0.5, m2.fract(kilogram).get(kilogram), epsilon = EPSILON);
}

#[test]
fn conversion() {
assert_eq!(1000.0, kilometer::conversion());
Expand Down Expand Up @@ -434,6 +544,116 @@ macro_rules! test {
ulps_eq!(1.0, m1.get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn floor() {
let l1 = k::TLength::new::<kilometer>(3.9999);
let l2 = k::TLength::new::<kilometer>(3.0001);
let l3 = k::TLength::new::<meter>(3.9999);
let l4 = k::TLength::new::<meter>(3.0001);
let m1 = k::TMass::new::<kilogram>(3.9999);
let m2 = k::TMass::new::<kilogram>(3.0001);

assert_eq!(3.0, l1.floor(kilometer).get(kilometer));
assert_eq!(3999.0, l1.floor(meter).get(meter));
assert_eq!(3.0, l2.floor(kilometer).get(kilometer));
assert_eq!(3000.0, l2.floor(meter).get(meter));
assert_eq!(0.0, l3.floor(kilometer).get(kilometer));
assert_eq!(3.0, l3.floor(meter).get(meter));
assert_eq!(0.0, l4.floor(kilometer).get(kilometer));
assert_eq!(3.0, l4.floor(meter).get(meter));
assert_eq!(3.0, m1.floor(kilogram).get(kilogram));
assert_eq!(3.0, m2.floor(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn ceil() {
let l1 = k::TLength::new::<kilometer>(3.9999);
let l2 = k::TLength::new::<kilometer>(3.0001);
let l3 = k::TLength::new::<meter>(3.9999);
let l4 = k::TLength::new::<meter>(3.0001);
let m1 = k::TMass::new::<kilogram>(3.9999);
let m2 = k::TMass::new::<kilogram>(3.0001);

assert_eq!(4.0, l1.ceil(kilometer).get(kilometer));
assert_eq!(4000.0, l1.ceil(meter).get(meter));
assert_eq!(4.0, l2.ceil(kilometer).get(kilometer));
assert_eq!(3001.0, l2.ceil(meter).get(meter));
assert_eq!(1.0, l3.ceil(kilometer).get(kilometer));
assert_eq!(4.0, l3.ceil(meter).get(meter));
assert_eq!(1.0, l4.ceil(kilometer).get(kilometer));
assert_eq!(4.0, l4.ceil(meter).get(meter));
assert_eq!(4.0, m1.ceil(kilogram).get(kilogram));
assert_eq!(4.0, m2.ceil(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn round() {
let l1 = k::TLength::new::<kilometer>(3.3);
let l2 = k::TLength::new::<kilometer>(3.5);
let l3 = k::TLength::new::<meter>(3.3);
let l4 = k::TLength::new::<meter>(3.5);
let m1 = k::TMass::new::<kilogram>(3.3);
let m2 = k::TMass::new::<kilogram>(3.5);

assert_eq!(3.0, l1.round(kilometer).get(kilometer));
assert_eq!(3300.0, l1.round(meter).get(meter));
assert_eq!(4.0, l2.round(kilometer).get(kilometer));
assert_eq!(3500.0, l2.round(meter).get(meter));
assert_eq!(0.0, l3.round(kilometer).get(kilometer));
assert_eq!(3.0, l3.round(meter).get(meter));
assert_eq!(0.0, l4.round(kilometer).get(kilometer));
assert_eq!(4.0, l4.round(meter).get(meter));
assert_eq!(3.0, m1.round(kilogram).get(kilogram));
assert_eq!(4.0, m2.round(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn trunc() {
let l1 = k::TLength::new::<kilometer>(3.3);
let l2 = k::TLength::new::<kilometer>(3.5);
let l3 = k::TLength::new::<meter>(3.3);
let l4 = k::TLength::new::<meter>(3.5);
let m1 = k::TMass::new::<kilogram>(3.3);
let m2 = k::TMass::new::<kilogram>(3.5);

assert_eq!(3.0, l1.trunc(kilometer).get(kilometer));
assert_eq!(3300.0, l1.trunc(meter).get(meter));
assert_eq!(3.0, l2.trunc(kilometer).get(kilometer));
assert_eq!(3500.0, l2.trunc(meter).get(meter));
assert_eq!(0.0, l3.trunc(kilometer).get(kilometer));
assert_eq!(3.0, l3.trunc(meter).get(meter));
assert_eq!(0.0, l4.trunc(kilometer).get(kilometer));
assert_eq!(3.0, l4.trunc(meter).get(meter));
assert_eq!(3.0, m1.trunc(kilogram).get(kilogram));
assert_eq!(3.0, m2.trunc(kilogram).get(kilogram));
}

#[cfg(feature = "std")]
#[test]
fn fract() {
let l1 = k::TLength::new::<kilometer>(3.3);
let l2 = k::TLength::new::<kilometer>(3.5);
let l3 = k::TLength::new::<meter>(3.3);
let l4 = k::TLength::new::<meter>(3.5);
let m1 = k::TMass::new::<kilogram>(3.3);
let m2 = k::TMass::new::<kilogram>(3.5);

ulps_eq!(0.3, l1.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.0, l1.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.0, l2.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.5, l2.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.0033, l3.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.3, l3.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.00035, l4.fract(kilometer).get(kilometer), epsilon = EPSILON);
ulps_eq!(0.5, l4.fract(meter).get(meter), epsilon = EPSILON);
ulps_eq!(0.3, m1.fract(kilogram).get(kilogram), epsilon = EPSILON);
ulps_eq!(0.5, m2.fract(kilogram).get(kilogram), epsilon = EPSILON);
}

quickcheck! {
#[allow(trivial_casts)]
fn add(l: $V, r: $V) -> bool {
Expand Down

0 comments on commit feb2450

Please sign in to comment.