unit_interval/lib.rs
1#![deny(missing_docs)]
2#![deny(rustdoc::broken_intra_doc_links)]
3#![deny(rustdoc::invalid_rust_codeblocks)]
4#![deny(rustdoc::missing_crate_level_docs)]
5#![warn(rustdoc::invalid_codeblock_attributes)]
6//! A small crate for working with numbers in the unit interval.
7//!
8//! This crate currently only provides the [`UnitInterval`] type, which represents a number
9//! constrained to the closed interval between 0 and 1, inclusive. It offers
10//! operations, bounds checking, and utilities for working with
11//! values in this range.
12//!
13//! ## Quick Start
14//!
15//! To get started, create a `UnitInterval` using one of the many constructor methods:
16//!
17//! ```rust
18//! use unit_interval::UnitInterval;
19//!
20//! // Create a UnitInterval, panics if out of bounds
21//! let a = UnitInterval::new(0.5);
22//!
23//! // Create a UnitInterval, returns a Result
24//! let b = UnitInterval::new_checked(0.75).unwrap();
25//!
26//! // Create a UnitInterval, clamping the value to [0, 1]
27//! let c = UnitInterval::new_clamped(1.5);
28//! assert_eq!(c.into_inner(), 1.0);
29//! ```
30//!
31//! Perform operations on `UnitInterval` values:
32//!
33//! ```rust
34//! use unit_interval::UnitInterval;
35//!
36//! let a = UnitInterval::new(0.3);
37//! let b = UnitInterval::new(0.5);
38//!
39//! // Multiplication always stays within [0, 1]
40//! let product = a * b;
41//! assert_eq!(product.into_inner(), 0.15);
42//!
43//! // Other operations may need checking or clamping
44//! let sum = a.checked_add(b).unwrap();
45//! let difference = a.clamped_sub(b);
46//! ```
47
48use core::borrow::Borrow;
49use core::error;
50use core::fmt::{self, Debug, Display};
51use core::ops::{Add, Div, Mul, Sub};
52
53use num_traits::{float::FloatCore, One, Zero};
54
55/// A number in the closed [unit interval](https://en.wikipedia.org/wiki/Unit_interval) \[0, 1\]
56///
57/// The precise invariant is that for an underlying value `v` of type `T` is
58/// `T::zero() <= v` and `v <= T::one()` where [`Zero`] and [`One`] are traits
59/// from from the [num-traits] crate.
60///
61/// Unlike [`NonZero`](core::num::NonZero) types, this type does not reserve any bit-patterns
62/// and simply guarantee that the value inside will not exceed the bounds via construction.
63/// Unsoundly constructing a value of this type that exceed its bounds will not result in immediate
64/// undefined behavior.
65///
66/// # Examples
67/// ```
68/// use unit_interval::UnitInterval;
69///
70/// let full = UnitInterval::one();
71/// let half = UnitInterval::new(0.5);
72///
73/// assert_eq!(full + half, 1.5);
74/// assert_eq!(half - full, -0.5);
75/// assert_eq!(half * full, UnitInterval::new(0.5));
76/// assert_eq!(full / half, 2.0);
77///
78/// assert_eq!(full.into_inner(), 1.0);
79/// assert_eq!(half.into_inner(), 0.5);
80/// ```
81///
82/// [`num-traits`]: https://crates.io/crates/num-traits
83#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
84#[repr(transparent)]
85pub struct UnitInterval<T>(T);
86
87/// An error type representing a value that falls outside the closed unit interval \[0, 1\]
88///
89/// This type is returned by operations that may produce values outside the unit interval,
90/// providing information about how the value exceeds the bounds.
91#[derive(Clone, Copy, PartialEq, Eq)]
92pub struct BoundError<T> {
93 kind: BoundErrorKind,
94 val: T,
95}
96impl<T> BoundError<T> {
97 #[inline]
98 const fn new(kind: BoundErrorKind, val: T) -> Self {
99 Self { kind, val }
100 }
101 #[inline]
102 const fn less_than_zero(val: T) -> Self {
103 Self::new(BoundErrorKind::LessThanZero, val)
104 }
105 #[inline]
106 const fn greater_than_one(val: T) -> Self {
107 Self::new(BoundErrorKind::GreaterThanOne, val)
108 }
109 #[inline]
110 const fn neither(val: T) -> Self {
111 Self::new(BoundErrorKind::Neither, val)
112 }
113
114 /// The way in which the value is out of bounds.
115 ///
116 /// For more detail, see [BoundErrorKind].
117 #[inline]
118 pub const fn kind(&self) -> BoundErrorKind {
119 self.kind
120 }
121 /// The value that caused the error.
122 ///
123 /// The same one used in the attempted creation of a [`UnitInterval`].
124 #[inline]
125 pub fn value(self) -> T {
126 self.val
127 }
128}
129impl<T: Debug> Debug for BoundError<T> {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 match self.kind {
132 BoundErrorKind::LessThanZero => {
133 write!(f, "{:?} compares less than zero", self.val)
134 }
135 BoundErrorKind::GreaterThanOne => {
136 write!(f, "{:?} compares greater than one", self.val)
137 }
138 BoundErrorKind::Neither => write!(
139 f,
140 "{:?} compares neither greater than or equal to zero nor less than or equal to one",
141 self.val
142 ),
143 }
144 }
145}
146impl<T: Display> Display for BoundError<T> {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 match self.kind {
149 BoundErrorKind::LessThanZero => write!(f, "{} compares less than zero", self.val),
150 BoundErrorKind::GreaterThanOne => {
151 write!(f, "{} compares greater than one", self.val)
152 }
153 BoundErrorKind::Neither => write!(
154 f,
155 "{} compares neither greater than or equal to zero nor less than or equal to one",
156 self.val
157 ),
158 }
159 }
160}
161
162impl<T: Debug + Display> error::Error for BoundError<T> {}
163
164/// Describes how a value falls outside the closed unit interval [0, 1]
165///
166/// # Examples
167/// ```
168/// use unit_interval::{UnitInterval, BoundErrorKind};
169///
170/// let result = UnitInterval::new_checked(-0.5);
171/// assert_eq!(result.unwrap_err().kind(), BoundErrorKind::LessThanZero);
172///
173/// let result = UnitInterval::new_checked(1.5);
174/// assert_eq!(result.unwrap_err().kind(), BoundErrorKind::GreaterThanOne);
175///
176/// let result = UnitInterval::new_checked(f32::NAN);
177/// assert_eq!(result.unwrap_err().kind(), BoundErrorKind::Neither);
178/// ```
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
181pub enum BoundErrorKind {
182 /// The value is less than both zero and one
183 ///
184 /// When `T::zero() <= val` is false but `val <= T::one()` is true.
185 LessThanZero,
186 /// The value is greater than both zero and one
187 ///
188 /// When `T::zero() <= val` is true but `val <= T::one()` is false.
189 GreaterThanOne,
190 /// The value is neither greater than or equal to zero nor less than or equal to one
191 ///
192 /// When both `T::zero() <= val` and `val <= T::one()` are false.
193 ///
194 /// This can mean 2 things:
195 /// 1. The value is [NaN]-like
196 /// 2. The comparison operations ([`PartialOrd`]) or [`Zero`] or [`One`]
197 /// are incorrectly implemented for the type of the value
198 ///
199 /// [NaN]: https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN
200 Neither,
201}
202
203impl<T: Zero + One + PartialOrd> UnitInterval<T> {
204 /// Guarantee the number in the closed unit interval if
205 /// `T::zero() <= val` and `val <= T::one()`, else returns an error
206 /// detailing which bound was crossed.
207 #[inline]
208 pub fn new_checked(val: T) -> Result<Self, BoundError<T>> {
209 match (T::zero() <= val, val <= T::one()) {
210 (true, true) => Ok(Self(val)),
211 (true, false) => Err(BoundError::greater_than_one(val)),
212 (false, true) => Err(BoundError::less_than_zero(val)),
213 (false, false) => Err(BoundError::neither(val)),
214 }
215 }
216 /// Guarantee the number in the closed unit interval, clamping the value
217 /// if it exceed the bounds in either direction.
218 ///
219 /// # Panics
220 /// Panics if the value exceed the bounds in both direction
221 /// (see [`BoundErrorKind::Neither`]).
222 ///
223 /// # Examples
224 /// ```
225 /// use unit_interval::UnitInterval;
226 ///
227 /// assert_eq!(UnitInterval::new_clamped(2).into_inner(), 1);
228 /// assert_eq!(UnitInterval::new_clamped(-5).into_inner(), 0);
229 /// ```
230 ///
231 /// NaN is an example of when this function panics
232 /// ```should_panic
233 /// use unit_interval::UnitInterval;
234 ///
235 /// let _ = UnitInterval::new_clamped(f32::NAN);
236 /// ```
237 #[inline]
238 #[must_use]
239 pub fn new_clamped(val: T) -> Self {
240 let zero = T::zero();
241 let one = T::one();
242 match (zero <= val, val <= one) {
243 (true, true) => Self(val),
244 (true, false) => Self(one),
245 (false, true) => Self(zero),
246 (false, false) => {
247 panic!("Value must compare greater equal to zero OR less equal to one")
248 }
249 }
250 }
251 /// Guarantee the number in the closed unit interval, panicking if not.
252 ///
253 /// # Panics
254 /// Panics if the number is not within the unit interval.
255 #[inline]
256 #[must_use]
257 pub fn new(val: T) -> Self
258 where
259 T: Debug,
260 {
261 Self::new_checked(val).expect("Value must be in the interval [0, 1]")
262 }
263}
264impl<T: FloatCore> UnitInterval<T> {
265 /// Guarantee the number in the closed unit interval by taking only
266 /// its fractional part.
267 ///
268 /// This cannot fail as the fractional part of a number is off the range [0, 1),
269 /// which is a subset of \[0, 1\].
270 #[inline]
271 #[must_use]
272 pub fn new_fract(val: T) -> Self {
273 Self(val.fract())
274 }
275}
276impl<T> UnitInterval<T> {
277 /// Assumes that the number is in the closed unit interval.
278 ///
279 /// # Safety
280 /// Improper usage of this function should only lead to logic error and not undefined behavior
281 /// as long as no further unsafe code rely on the guarantee granted by this type.
282 #[inline]
283 #[must_use]
284 pub const unsafe fn new_unchecked(val: T) -> Self {
285 Self(val)
286 }
287
288 /// Returns a reference to the inner value.
289 #[inline]
290 pub const fn as_inner(&self) -> &T {
291 &self.0
292 }
293 /// Consumes the `UnitInterval` and returns the inner value.
294 #[inline]
295 pub fn into_inner(self) -> T {
296 self.0
297 }
298}
299impl<T: Zero> UnitInterval<T> {
300 /// Creates a new `UnitInterval` with a value of zero.
301 ///
302 /// # Examples
303 /// ```
304 /// use unit_interval::UnitInterval;
305 ///
306 /// let zero = UnitInterval::<f32>::zero();
307 /// assert_eq!(zero.into_inner(), 0.0);
308 /// ```
309 #[inline]
310 pub fn zero() -> Self {
311 Self(T::zero())
312 }
313}
314impl<T: One> UnitInterval<T> {
315 /// Creates a new `UnitInterval` with a value of one.
316 ///
317 /// # Examples
318 /// ```
319 /// use unit_interval::UnitInterval;
320 ///
321 /// let one = UnitInterval::<f32>::one();
322 /// assert_eq!(one.into_inner(), 1.0);
323 /// ```
324 #[inline]
325 pub fn one() -> Self {
326 Self(T::one())
327 }
328 /// Returns the complement of the currently held value.
329 ///
330 /// # Examples
331 /// ```
332 /// use unit_interval::UnitInterval;
333 ///
334 /// let a = UnitInterval::new(0.2);
335 /// assert_eq!(a.complement(), UnitInterval::new(0.8));
336 /// ```
337 #[inline]
338 pub fn complement(self) -> UnitInterval<<T as Sub>::Output>
339 where
340 T: Sub,
341 {
342 UnitInterval(T::one() - self.0)
343 }
344}
345
346impl<T: Add> UnitInterval<T>
347where
348 T::Output: Zero + One + PartialOrd,
349{
350 /// Adds a value inside the close unit interval to produce another.
351 ///
352 /// Equivalent to adding the inner values then using [`UnitInterval::new_checked`].
353 ///
354 /// # Examples
355 /// ```
356 /// use unit_interval::{UnitInterval, BoundErrorKind};
357 ///
358 /// let a = UnitInterval::new(0.5);
359 /// let b = UnitInterval::new(0.75);
360 /// let result = a.checked_add(b);
361 /// assert_eq!(result, UnitInterval::new_checked(0.5 + 0.75));
362 /// let err = result.unwrap_err();
363 /// assert_eq!(err.kind(), BoundErrorKind::GreaterThanOne);
364 /// assert_eq!(err.value(), 1.25);
365 /// ```
366 #[inline]
367 pub fn checked_add(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
368 UnitInterval::new_checked(self.0 + rhs.0)
369 }
370 /// Adds two `UnitInterval` values, clamping the result to the unit interval.
371 ///
372 /// # Examples
373 /// ```
374 /// use unit_interval::UnitInterval;
375 ///
376 /// let a = UnitInterval::new(0.7);
377 /// let b = UnitInterval::new(0.6);
378 /// let result = a.clamped_add(b);
379 /// assert_eq!(result.into_inner(), 1.0);
380 /// ```
381 #[inline]
382 pub fn clamped_add(self, rhs: Self) -> UnitInterval<T::Output> {
383 UnitInterval::new_clamped(self.0 + rhs.0)
384 }
385}
386impl<T: Sub> UnitInterval<T>
387where
388 T::Output: Zero + One + PartialOrd,
389{
390 /// Subtracts a value inside the close unit interval to produce another.
391 ///
392 /// Equivalent to subtracting the inner values then using [`UnitInterval::new_checked`].
393 ///
394 /// # Examples
395 /// ```
396 /// use unit_interval::{UnitInterval, BoundErrorKind};
397 ///
398 /// let a = UnitInterval::new(0.4);
399 /// let b = UnitInterval::new(0.8);
400 /// let result = a.checked_sub(b);
401 /// assert_eq!(result, UnitInterval::new_checked(0.4 - 0.8));
402 /// let err = result.unwrap_err();
403 /// assert_eq!(err.kind(), BoundErrorKind::LessThanZero);
404 /// assert_eq!(err.value(), -0.4);
405 /// ```
406 #[inline]
407 pub fn checked_sub(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
408 UnitInterval::new_checked(self.0 - rhs.0)
409 }
410 /// Subtracts one `UnitInterval` from another, clamping the result to the unit interval.
411 ///
412 /// # Examples
413 /// ```
414 /// use unit_interval::UnitInterval;
415 ///
416 /// let a = UnitInterval::new(0.3);
417 /// let b = UnitInterval::new(0.6);
418 /// let result = a.clamped_sub(b);
419 /// assert_eq!(result.into_inner(), 0.0);
420 /// ```
421 #[inline]
422 pub fn clamped_sub(self, rhs: Self) -> UnitInterval<T::Output> {
423 UnitInterval::new_clamped(self.0 - rhs.0)
424 }
425}
426impl<T: Mul> UnitInterval<T>
427where
428 T::Output: Zero + One + PartialOrd,
429{
430 /// Multiplies a value inside the close unit interval to produce another.
431 ///
432 /// Equivalent to multiplying the inner values then using [`UnitInterval::new_checked`].
433 ///
434 /// Note: Multiplication of two values in [0, 1] always results in a value in [0, 1],
435 /// so checking is not strictly necessary for this operation.
436 ///
437 /// # Examples
438 /// ```
439 /// use unit_interval::UnitInterval;
440 ///
441 /// let a = UnitInterval::new(0.5);
442 /// let b = UnitInterval::new(0.6);
443 /// let result = a.checked_mul(b);
444 /// assert_eq!(result, UnitInterval::new_checked(0.5 * 0.6));
445 /// let ok = result.unwrap();
446 /// assert_eq!(ok.into_inner(), 0.3);
447 /// ```
448 #[inline]
449 pub fn checked_mul(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
450 UnitInterval::new_checked(self.0 * rhs.0)
451 }
452 /// Multiplies two `UnitInterval` values, clamping the result to the unit interval.
453 ///
454 /// Note: Multiplication of two values in [0, 1] always results in a value in [0, 1],
455 /// so clamping is not strictly necessary for this operation.
456 ///
457 /// # Examples
458 /// ```
459 /// use unit_interval::UnitInterval;
460 ///
461 /// let a = UnitInterval::new(0.5);
462 /// let b = UnitInterval::new(0.6);
463 /// let result = a.clamped_mul(b);
464 /// assert_eq!(result.into_inner(), 0.3);
465 /// ```
466 #[inline]
467 pub fn clamped_mul(self, rhs: Self) -> UnitInterval<T::Output> {
468 UnitInterval::new_clamped(self.0 * rhs.0)
469 }
470}
471impl<T: Div> UnitInterval<T>
472where
473 T::Output: Zero + One + PartialOrd,
474{
475 /// Divides a value inside the close unit interval to produce another.
476 ///
477 /// Equivalent to dividing the inner values then using [`UnitInterval::new_checked`].
478 ///
479 /// # Examples
480 /// ```
481 /// use unit_interval::{UnitInterval, BoundErrorKind};
482 ///
483 /// let a = UnitInterval::new(0.8);
484 /// let b = UnitInterval::new(0.4);
485 /// let result = a.checked_div(b);
486 /// assert_eq!(result, UnitInterval::new_checked(0.8 / 0.4));
487 /// let err = result.unwrap_err();
488 /// assert_eq!(err.kind(), BoundErrorKind::GreaterThanOne);
489 /// assert_eq!(err.value(), 2.0);
490 /// ```
491 #[inline]
492 pub fn checked_div(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
493 UnitInterval::new_checked(self.0 / rhs.0)
494 }
495 /// Divides one `UnitInterval` by another, clamping the result to the unit interval.
496 ///
497 /// # Examples
498 /// ```
499 /// use unit_interval::UnitInterval;
500 ///
501 /// let a = UnitInterval::new(0.8);
502 /// let b = UnitInterval::new(0.4);
503 /// let result = a.clamped_div(b);
504 /// assert_eq!(result.into_inner(), 1.0);
505 /// ```
506 #[inline]
507 pub fn clamped_div(self, rhs: Self) -> UnitInterval<T::Output> {
508 UnitInterval::new_clamped(self.0 / rhs.0)
509 }
510}
511
512impl<T: One> One for UnitInterval<T> {
513 #[inline]
514 fn one() -> Self {
515 UnitInterval::one()
516 }
517}
518
519impl<T: Add> Add<T> for UnitInterval<T> {
520 type Output = T::Output;
521
522 #[inline]
523 fn add(self, rhs: T) -> Self::Output {
524 self.0 + rhs
525 }
526}
527impl<T: Sub> Sub<T> for UnitInterval<T> {
528 type Output = T::Output;
529
530 #[inline]
531 fn sub(self, rhs: T) -> Self::Output {
532 self.0 - rhs
533 }
534}
535impl<T: Mul> Mul<T> for UnitInterval<T> {
536 type Output = T::Output;
537
538 #[inline]
539 fn mul(self, rhs: T) -> Self::Output {
540 self.0 * rhs
541 }
542}
543impl<T: Div> Div<T> for UnitInterval<T> {
544 type Output = T::Output;
545
546 #[inline]
547 fn div(self, rhs: T) -> Self::Output {
548 self.0 / rhs
549 }
550}
551
552impl<T: Add> Add for UnitInterval<T> {
553 type Output = T::Output;
554
555 #[inline]
556 fn add(self, rhs: Self) -> Self::Output {
557 self.0 + rhs.0
558 }
559}
560impl<T: Sub> Sub for UnitInterval<T> {
561 type Output = T::Output;
562
563 #[inline]
564 fn sub(self, rhs: Self) -> Self::Output {
565 self.0 - rhs.0
566 }
567}
568impl<T: Mul> Mul for UnitInterval<T> {
569 type Output = UnitInterval<T::Output>;
570
571 #[inline]
572 fn mul(self, rhs: UnitInterval<T>) -> Self::Output {
573 UnitInterval(self.0 * rhs.0)
574 }
575}
576impl<T: Div> Div for UnitInterval<T> {
577 type Output = T::Output;
578
579 #[inline]
580 fn div(self, rhs: Self) -> Self::Output {
581 self.0 / rhs.0
582 }
583}
584
585impl<T> AsRef<T> for UnitInterval<T> {
586 #[inline]
587 fn as_ref(&self) -> &T {
588 self.as_inner()
589 }
590}
591impl<T> Borrow<T> for UnitInterval<T> {
592 #[inline]
593 fn borrow(&self) -> &T {
594 self.as_inner()
595 }
596}
597
598#[cfg(test)]
599mod tests {
600 use super::*;
601
602 use core::cmp::Ordering;
603 use core::f64;
604
605 const EPSILON: f64 = 1e-4;
606 macro_rules! assert_float_eq {
607 ($a:expr, $b:expr) => {
608 let left: f64 = $a;
609 let right: f64 = $b;
610 match (left - right).abs().partial_cmp(&EPSILON) {
611 None | Some(Ordering::Greater) => assert_eq!(left, right),
612 _ => {}
613 }
614 };
615 }
616
617 #[test]
618 fn new() {
619 assert_eq!(UnitInterval::new(0.5).into_inner(), 0.5);
620 assert_eq!(UnitInterval::new(0.0).into_inner(), 0.0);
621 assert_eq!(UnitInterval::new(1.0).into_inner(), 1.0);
622 }
623
624 #[test]
625 fn new_negative_zero() {
626 let _ = UnitInterval::new(-0.0);
627 }
628
629 #[test]
630 #[should_panic(expected = "Value must be in the interval [0, 1]: -0.1 compares less than zero")]
631 fn new_panic_less_than_zero() {
632 let _ = UnitInterval::new(-0.1);
633 }
634
635 #[test]
636 #[should_panic(
637 expected = "Value must be in the interval [0, 1]: 1.1 compares greater than one"
638 )]
639 fn new_panic_greater_than_one() {
640 let _ = UnitInterval::new(1.1);
641 }
642
643 #[test]
644 fn new_checked() {
645 assert!(UnitInterval::new_checked(0.5).is_ok());
646 assert!(UnitInterval::new_checked(0.0).is_ok());
647 assert!(UnitInterval::new_checked(1.0).is_ok());
648
649 let err = UnitInterval::new_checked(-0.1).unwrap_err();
650 assert_eq!(err.kind(), BoundErrorKind::LessThanZero);
651 assert_float_eq!(err.value(), -0.1);
652
653 let err = UnitInterval::new_checked(1.1).unwrap_err();
654 assert_eq!(err.kind(), BoundErrorKind::GreaterThanOne);
655 assert_float_eq!(err.value(), 1.1);
656
657 let err = UnitInterval::new_checked(f64::NAN).unwrap_err();
658 assert_eq!(err.kind(), BoundErrorKind::Neither);
659 assert!(err.value().is_nan());
660 }
661
662 #[test]
663 fn new_clamped() {
664 assert_float_eq!(UnitInterval::new_clamped(0.5).into_inner(), 0.5);
665 assert_float_eq!(UnitInterval::new_clamped(-0.1).into_inner(), 0.0);
666 assert_float_eq!(UnitInterval::new_clamped(1.1).into_inner(), 1.0);
667 }
668
669 #[test]
670 fn new_fract() {
671 assert_float_eq!(UnitInterval::new_fract(1.5).into_inner(), 0.5);
672 assert_float_eq!(UnitInterval::new_fract(2.75).into_inner(), 0.75);
673 assert_float_eq!(UnitInterval::new_fract(-1.25).into_inner(), -0.25);
674 }
675
676 #[test]
677 fn as_inner() {
678 let unit = UnitInterval::new(0.5);
679 assert_float_eq!(*unit.as_inner(), 0.5);
680 }
681
682 #[test]
683 fn into_inner() {
684 let unit = UnitInterval::new(0.5);
685 assert_float_eq!(unit.into_inner(), 0.5);
686 }
687
688 #[test]
689 fn zero() {
690 assert_float_eq!(UnitInterval::<f64>::zero().into_inner(), 0.0);
691 }
692
693 #[test]
694 fn one() {
695 assert_float_eq!(UnitInterval::<f64>::one().into_inner(), 1.0);
696 }
697
698 #[test]
699 fn complement() {
700 assert_float_eq!(UnitInterval::new(0.3).complement().into_inner(), 0.7);
701 assert_float_eq!(UnitInterval::new(1.0).complement().into_inner(), 0.0);
702 assert_float_eq!(UnitInterval::new(0.0).complement().into_inner(), 1.0);
703 }
704
705 #[test]
706 fn checked_add() {
707 let a = UnitInterval::new(0.3);
708 let b = UnitInterval::new(0.4);
709 assert_float_eq!(a.checked_add(b).unwrap().into_inner(), 0.7f64);
710
711 let a = UnitInterval::new(0.7);
712 let b = UnitInterval::new(0.4);
713 assert!(a.checked_add(b).is_err());
714 }
715
716 #[test]
717 fn checked_sub() {
718 let a = UnitInterval::new(0.7);
719 let b = UnitInterval::new(0.4);
720 assert_float_eq!(a.checked_sub(b).unwrap().into_inner(), 0.3);
721
722 let a = UnitInterval::new(0.3);
723 let b = UnitInterval::new(0.4);
724 assert!(a.checked_sub(b).is_err());
725 }
726
727 #[test]
728 fn checked_mul() {
729 let a = UnitInterval::new(0.5);
730 let b = UnitInterval::new(0.6);
731 assert_float_eq!(a.checked_mul(b).unwrap().into_inner(), 0.3);
732 }
733
734 #[test]
735 fn checked_div() {
736 let a = UnitInterval::new(0.5);
737 let b = UnitInterval::new(0.25);
738 assert!(a.checked_div(b).is_err());
739
740 let a = UnitInterval::new(0.25);
741 let b = UnitInterval::new(0.5);
742 assert_float_eq!(a.checked_div(b).unwrap().into_inner(), 0.5);
743 }
744
745 #[test]
746 fn clamped_add() {
747 let a = UnitInterval::new(0.7);
748 let b = UnitInterval::new(0.4);
749 assert_float_eq!(a.clamped_add(b).into_inner(), 1.0);
750 }
751
752 #[test]
753 fn clamped_sub() {
754 let a = UnitInterval::new(0.3);
755 let b = UnitInterval::new(0.4);
756 assert_float_eq!(a.clamped_sub(b).into_inner(), 0.0);
757 }
758
759 #[test]
760 fn clamped_mul() {
761 let a = UnitInterval::new(0.5);
762 let b = UnitInterval::new(0.6);
763 assert_float_eq!(a.clamped_mul(b).into_inner(), 0.3);
764 }
765
766 #[test]
767 fn clamped_div() {
768 let a = UnitInterval::new(0.5);
769 let b = UnitInterval::new(0.25);
770 assert_float_eq!(a.clamped_div(b).into_inner(), 1.0);
771 }
772
773 #[test]
774 fn add() {
775 let a = UnitInterval::new(0.3);
776 let b = UnitInterval::new(0.4);
777 assert_float_eq!(a + b, 0.7);
778 }
779
780 #[test]
781 fn sub() {
782 let a = UnitInterval::new(0.7);
783 let b = UnitInterval::new(0.4);
784 assert_float_eq!(a - b, 0.3);
785 }
786
787 #[test]
788 fn mul() {
789 let a = UnitInterval::new(0.5);
790 let b = UnitInterval::new(0.6);
791 assert_float_eq!((a * b).into_inner(), 0.3);
792 }
793
794 #[test]
795 fn div() {
796 let a = UnitInterval::new(0.5);
797 let b = UnitInterval::new(0.25);
798 assert_float_eq!(a / b, 2.0);
799 }
800}