Skip to main content

fix/
lib.rs

1//! Fixed-point number types.
2//!
3//! # What?
4//!
5//! Fixed-point is a number representation with a fixed number of digits before and after the radix
6//! point. This means that range is static rather than dynamic, as with floating-point. It also
7//! means that they can be represented as integers, with their scale tracked by the type system.
8//!
9//! In this library, the scale of a `Fix` is represented as two type-level integers: the base and
10//! the exponent. Any underlying integer primitive can be used to store the number. Arithmetic can
11//! be performed on these numbers, and they can be converted to different scale exponents.
12//!
13//! # Why?
14//!
15//! A classic example: let's sum 10 cents and 20 cents using floating-point. We expect a result of
16//! 30 cents.
17//!
18//! ```should_panic
19//! assert_eq!(0.30, 0.10 + 0.20);
20//! ```
21//!
22//! Wrong! We get an extra forty quintillionths of a dollar.
23//!
24//! ```text
25//! assertion failed: `(left == right)` (left: `0.3`, right: `0.30000000000000004`)'
26//! ```
27//!
28//! This is due to neither 0.1 nor 0.2 being exactly representable in base-2, just as a third can't
29//! be represented exactly in base-10. With `Fix`, we can choose the precision we want in base-10,
30//! at compile-time. In this case, hundredths of a dollar will do.
31//!
32//! ```
33//! use fix::aliases::si::Centi; // Fix<_, U10, N2>
34//! assert_eq!(Centi::new(0_30), Centi::new(0_10) + Centi::new(0_20));
35//! ```
36//!
37//! But decimal is inefficient for binary computers, right? Multiplying and dividing by 10 is
38//! slower than bit-shifting, but that's only needed when _moving_ the point. With `Fix`, this is
39//! only done explicitly with the `convert` method.
40//!
41//! ```
42//! use fix::aliases::si::{Centi, Milli};
43//! assert_eq!(Milli::new(0_300), Centi::new(0_30).convert());
44//! ```
45//!
46//! We can also choose a base-2 scale just as easily.
47//!
48//! ```
49//! use fix::aliases::iec::{Kibi, Mebi};
50//! assert_eq!(Kibi::new(1024), Mebi::new(1).convert());
51//! ```
52//!
53//! It's also worth noting that the type-level scale changes when multiplying and dividing,
54//! avoiding any implicit conversion.
55//!
56//! ```
57//! use fix::aliases::iec::{Gibi, Kibi, Mebi};
58//! assert_eq!(Mebi::new(3), Gibi::new(6) / Kibi::new(2));
59//! ```
60//!
61//! # `no_std`
62//!
63//! This crate is `no_std`.
64
65#![no_std]
66
67#[cfg(feature = "std")]
68extern crate std;
69
70#[cfg(feature = "alloc")]
71extern crate alloc;
72
73pub extern crate muldiv;
74pub extern crate num_traits;
75#[cfg(feature = "typed-floats")]
76pub extern crate typed_floats;
77pub extern crate typenum;
78
79pub mod aliases;
80pub mod fix_value;
81pub mod prelude;
82pub mod util;
83
84use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
85#[cfg(feature = "alloc")]
86use core::fmt::Display;
87use core::fmt::{Debug, Error, Formatter};
88use core::hash::{Hash, Hasher};
89use core::marker::PhantomData;
90use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
91use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
92
93use muldiv::MulDiv;
94use num_traits::{
95    CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, ConstZero, SaturatingAdd, SaturatingSub,
96};
97use paste::paste;
98#[cfg(feature = "alloc")]
99use typenum::consts::U10;
100use typenum::consts::Z0;
101
102#[cfg(feature = "alloc")]
103use alloc::string::ToString;
104use typenum::marker_traits::{Bit, Integer, Unsigned};
105use typenum::operator_aliases::{AbsVal, Diff, Le, Sum};
106use typenum::type_operators::{Abs, IsLess};
107
108/// Fixed-point number representing _Bits × Base <sup>Exp</sup>_.
109///
110/// - `Bits` is an integer primitive type, or any type which can be created from a type-level
111///   integer and exponentiated.
112/// - `Base` is an [`Unsigned`] type-level integer.
113/// - `Exp` is a signed type-level [`Integer`].
114///
115/// [`Unsigned`]: ../typenum/marker_traits/trait.Unsigned.html
116/// [`Integer`]: ../typenum/marker_traits/trait.Integer.html
117///
118/// # Summary of operations
119///
120/// Lower case variables represent values of _Bits_. Upper case _B_ and _E_ represent type-level
121/// integers _Base_ and _Exp_, respectively.
122///
123/// - _−(x B<sup>E</sup>) = (−x) B<sup>E</sup>_
124/// - _(x B<sup>E</sup>) + (y B<sup>E</sup>) = (x + y) B<sup>E</sup>_
125/// - _(x B<sup>E</sup>) − (y B<sup>E</sup>) = (x − y) B<sup>E</sup>_
126/// - _(x B<sup>E<sub>x</sub></sup>) × (y B<sup>E<sub>y</sub></sup>) =
127///   (x × y) B<sup>E<sub>x</sub> + E<sub>y</sub></sup>_
128/// - _(x B<sup>E<sub>x</sub></sup>) ÷ (y B<sup>E<sub>y</sub></sup>) =
129///   (x ÷ y) B<sup>E<sub>x</sub> − E<sub>y</sub></sup>_
130/// - _(x B<sup>E<sub>x</sub></sup>) % (y B<sup>E<sub>y</sub></sup>) =
131///   (x % y) B<sup>E<sub>x</sub></sup>_
132/// - _(x B<sup>E</sup>) × y = (x × y) B<sup>E</sup>_
133/// - _(x B<sup>E</sup>) ÷ y = (x ÷ y) B<sup>E</sup>_
134/// - _(x B<sup>E</sup>) % y = (x % y) B<sup>E</sup>_
135pub struct Fix<Bits, Base, Exp> {
136    /// The underlying integer.
137    pub bits: Bits,
138
139    marker: PhantomData<(Base, Exp)>,
140}
141
142impl<Bits, Base, Exp> Fix<Bits, Base, Exp> {
143    /// Creates a number.
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// use fix::aliases::si::{Kilo, Milli};
149    /// Milli::new(25); // 0.025
150    /// Kilo::new(25); // 25 000
151    /// ```
152    pub fn new(bits: Bits) -> Self {
153        Fix {
154            bits,
155            marker: PhantomData,
156        }
157    }
158
159    /// Like `Self::new`, but creates numbers in the constant context.
160    pub const fn constant(bits: Bits) -> Self {
161        Fix {
162            bits,
163            marker: PhantomData,
164        }
165    }
166
167    /// Converts to another _Exp_.
168    ///
169    /// # Examples
170    ///
171    /// ```
172    /// use fix::aliases::si::{Kilo, Milli};
173    /// let kilo = Kilo::new(5);
174    /// let milli = Milli::new(5_000_000);
175    /// assert_eq!(kilo, milli.convert());
176    /// assert_eq!(milli, kilo.convert());
177    /// ```
178    pub fn convert<ToExp>(self) -> Fix<Bits, Base, ToExp>
179    where
180        Bits: FromUnsigned + Pow + Mul<Output = Bits> + Div<Output = Bits>,
181        Base: Unsigned,
182        Exp: Sub<ToExp>,
183        Diff<Exp, ToExp>: Abs + IsLess<Z0>,
184        AbsVal<Diff<Exp, ToExp>>: Integer,
185    {
186        let base = Bits::from_unsigned::<Base>();
187        let diff = AbsVal::<Diff<Exp, ToExp>>::to_i32();
188        let inverse = Le::<Diff<Exp, ToExp>, Z0>::to_bool();
189
190        // FIXME: Would like to do this with typenum::Pow, but that
191        // seems to result in overflow evaluating requirements.
192        let ratio = base.pow(diff.unsigned_abs());
193
194        if inverse {
195            Fix::new(self.bits / ratio)
196        } else {
197            Fix::new(self.bits * ratio)
198        }
199    }
200
201    /// Converts the underlying bits to a wider type.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// use fix::aliases::si::Milli;
207    /// let one = Milli::new(16899u64);
208    /// let mapped = one.widen::<u128>();
209    /// assert_eq!(mapped, Milli::new(16899u128));
210    /// ```
211    ///
212    pub fn widen<ToBits>(self) -> Fix<ToBits, Base, Exp>
213    where
214        ToBits: From<Bits>,
215    {
216        Fix::<ToBits, Base, Exp>::new(self.bits.into())
217    }
218
219    /// Attempts to converts underlying bits to a narrower type.
220    /// Returns `None` if conversion fails.
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// use fix::aliases::si::Milli;
226    /// let one = Milli::new(16899u128);
227    /// let mapped = one.narrow::<u64>();
228    /// assert_eq!(mapped, Some(Milli::new(16899u64)));
229    /// ```
230    ///
231    pub fn narrow<ToBits>(self) -> Option<Fix<ToBits, Base, Exp>>
232    where
233        ToBits: TryFrom<Bits>,
234    {
235        self.bits.try_into().ok().map(Fix::<ToBits, Base, Exp>::new)
236    }
237}
238
239/// Conversion from type-level [`Unsigned`] integers.
240///
241/// Enables being generic over types which can be created from type-level integers. It should
242/// probably be in `typenum` itself...
243///
244/// [`Unsigned`]: ../typenum/marker_traits/trait.Unsigned.html
245pub trait FromUnsigned {
246    /// Creates a value from a type.
247    fn from_unsigned<U>() -> Self
248    where
249        U: Unsigned;
250}
251
252macro_rules! impl_from_unsigned {
253    ($ty:ident) => {
254        impl FromUnsigned for $ty {
255            fn from_unsigned<U: Unsigned>() -> Self {
256                paste! { U::[<to_$ty>]() }
257            }
258        }
259    };
260}
261
262impl_from_unsigned!(u8);
263impl_from_unsigned!(u16);
264impl_from_unsigned!(u32);
265impl_from_unsigned!(u64);
266impl_from_unsigned!(u128);
267impl_from_unsigned!(usize);
268impl_from_unsigned!(i8);
269impl_from_unsigned!(i16);
270impl_from_unsigned!(i32);
271impl_from_unsigned!(i64);
272impl_from_unsigned!(i128);
273impl_from_unsigned!(isize);
274
275/// Exponentiation.
276///
277/// Enables being generic over integers which can be exponentiated. Why must we do this, standard
278/// library?
279pub trait Pow {
280    /// Raises `self` to the power of `exp`.
281    #[must_use]
282    fn pow(self, exp: u32) -> Self;
283}
284
285macro_rules! impl_pow {
286    ($ty:ident) => {
287        impl Pow for $ty {
288            #[inline]
289            fn pow(self, exp: u32) -> Self {
290                self.pow(exp)
291            }
292        }
293    };
294}
295
296impl_pow!(u8);
297impl_pow!(u16);
298impl_pow!(u32);
299impl_pow!(u64);
300impl_pow!(u128);
301impl_pow!(usize);
302impl_pow!(i8);
303impl_pow!(i16);
304impl_pow!(i32);
305impl_pow!(i64);
306impl_pow!(i128);
307impl_pow!(isize);
308
309// The usual traits.
310
311impl<Bits, Base, Exp> Copy for Fix<Bits, Base, Exp> where Bits: Copy {}
312
313impl<Bits, Base, Exp> Clone for Fix<Bits, Base, Exp>
314where
315    Bits: Clone,
316{
317    fn clone(&self) -> Self {
318        Self::new(self.bits.clone())
319    }
320}
321
322impl<Bits, Base, Exp> Default for Fix<Bits, Base, Exp>
323where
324    Bits: Default,
325{
326    fn default() -> Self {
327        Self::new(Bits::default())
328    }
329}
330
331impl<Bits, Base, Exp> Fix<Bits, Base, Exp>
332where
333    Bits: ConstZero,
334{
335    #[must_use]
336    pub const fn zero() -> Self {
337        Self::constant(Bits::ZERO)
338    }
339}
340
341impl<Bits, Base, Exp> Hash for Fix<Bits, Base, Exp>
342where
343    Bits: Hash,
344{
345    fn hash<H>(&self, state: &mut H)
346    where
347        H: Hasher,
348    {
349        self.bits.hash(state);
350    }
351}
352
353impl<Bits, Base, Exp> Debug for Fix<Bits, Base, Exp>
354where
355    Bits: Debug,
356    Base: Unsigned,
357    Exp: Integer,
358{
359    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
360        write!(f, "{:?}x{}^{}", self.bits, Base::to_u64(), Exp::to_i64())
361    }
362}
363
364#[cfg(feature = "alloc")]
365impl<Bits, Exp> Display for Fix<Bits, U10, Exp>
366where
367    Bits: Display,
368    Exp: Integer,
369{
370    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
371        let exp = Exp::to_i32();
372        let decimals = usize::try_from(exp.unsigned_abs()).map_err(|_| Error)?;
373        let raw = self.bits.to_string();
374        let (sign, digits) = raw
375            .strip_prefix('-')
376            .map_or(("", raw.as_str()), |d| ("-", d));
377
378        match exp {
379            0.. => write!(f, "{sign}{digits}{}", "0".repeat(decimals)),
380            _ if digits.len() > decimals => {
381                let (integer, fraction) = digits.split_at(digits.len() - decimals);
382                write!(f, "{sign}{integer}.{fraction}")
383            }
384            _ => {
385                let padding = "0".repeat(decimals - digits.len());
386                write!(f, "{sign}0.{padding}{digits}")
387            }
388        }
389    }
390}
391
392// Comparison.
393
394impl<Bits, Base, Exp> Eq for Fix<Bits, Base, Exp> where Bits: Eq {}
395impl<Bits, Base, Exp> PartialEq for Fix<Bits, Base, Exp>
396where
397    Bits: PartialEq,
398{
399    fn eq(&self, rhs: &Self) -> bool {
400        self.bits == rhs.bits
401    }
402}
403
404impl<Bits, Base, Exp> PartialOrd for Fix<Bits, Base, Exp>
405where
406    Bits: PartialOrd,
407{
408    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
409        self.bits.partial_cmp(&rhs.bits)
410    }
411}
412
413impl<Bits, Base, Exp> Ord for Fix<Bits, Base, Exp>
414where
415    Bits: Ord,
416{
417    fn cmp(&self, rhs: &Self) -> Ordering {
418        self.bits.cmp(&rhs.bits)
419    }
420}
421
422// Arithmetic.
423
424impl<Bits, Base, Exp> Neg for Fix<Bits, Base, Exp>
425where
426    Bits: Neg<Output = Bits>,
427{
428    type Output = Self;
429    fn neg(self) -> Self {
430        Self::new(-self.bits)
431    }
432}
433
434impl<Bits, Base, Exp> Add for Fix<Bits, Base, Exp>
435where
436    Bits: Add<Output = Bits>,
437{
438    type Output = Self;
439    fn add(self, rhs: Self) -> Self {
440        Self::new(self.bits + rhs.bits)
441    }
442}
443
444impl<Bits, Base, Exp> Sub for Fix<Bits, Base, Exp>
445where
446    Bits: Sub<Output = Bits>,
447{
448    type Output = Self;
449    fn sub(self, rhs: Self) -> Self {
450        Self::new(self.bits - rhs.bits)
451    }
452}
453
454impl<Bits, Base, LExp, RExp> Mul<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
455where
456    Bits: Mul<Output = Bits>,
457    LExp: Add<RExp>,
458{
459    type Output = Fix<Bits, Base, Sum<LExp, RExp>>;
460    fn mul(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
461        Self::Output::new(self.bits * rhs.bits)
462    }
463}
464
465impl<Bits, Base, LExp, RExp> Div<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
466where
467    Bits: Div<Output = Bits>,
468    LExp: Sub<RExp>,
469{
470    type Output = Fix<Bits, Base, Diff<LExp, RExp>>;
471    fn div(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
472        Self::Output::new(self.bits / rhs.bits)
473    }
474}
475
476impl<Bits, Base, Exp> Rem for Fix<Bits, Base, Exp>
477where
478    Bits: Rem<Output = Bits>,
479{
480    type Output = Self;
481    fn rem(self, rhs: Self) -> Self {
482        Self::new(self.bits % rhs.bits)
483    }
484}
485
486impl<Bits, Base, Exp> Mul<Bits> for Fix<Bits, Base, Exp>
487where
488    Bits: Mul<Output = Bits>,
489{
490    type Output = Self;
491    fn mul(self, rhs: Bits) -> Self {
492        Self::new(self.bits * rhs)
493    }
494}
495
496impl<Bits, Base, Exp> Div<Bits> for Fix<Bits, Base, Exp>
497where
498    Bits: Div<Output = Bits>,
499{
500    type Output = Self;
501    fn div(self, rhs: Bits) -> Self {
502        Self::new(self.bits / rhs)
503    }
504}
505
506impl<Bits, Base, Exp> Rem<Bits> for Fix<Bits, Base, Exp>
507where
508    Bits: Rem<Output = Bits>,
509{
510    type Output = Self;
511    fn rem(self, rhs: Bits) -> Self {
512        Self::new(self.bits % rhs)
513    }
514}
515
516impl<Bits, Base, Exp> AddAssign for Fix<Bits, Base, Exp>
517where
518    Bits: AddAssign,
519{
520    fn add_assign(&mut self, rhs: Self) {
521        self.bits += rhs.bits;
522    }
523}
524
525impl<Bits, Base, Exp> SubAssign for Fix<Bits, Base, Exp>
526where
527    Bits: SubAssign,
528{
529    fn sub_assign(&mut self, rhs: Self) {
530        self.bits -= rhs.bits;
531    }
532}
533
534impl<Bits, Base, Exp> MulAssign<Bits> for Fix<Bits, Base, Exp>
535where
536    Bits: MulAssign,
537{
538    fn mul_assign(&mut self, rhs: Bits) {
539        self.bits *= rhs;
540    }
541}
542
543impl<Bits, Base, Exp> DivAssign<Bits> for Fix<Bits, Base, Exp>
544where
545    Bits: DivAssign,
546{
547    fn div_assign(&mut self, rhs: Bits) {
548        self.bits /= rhs;
549    }
550}
551
552impl<Bits, Base, LExp, RExp> RemAssign<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
553where
554    Bits: RemAssign,
555{
556    fn rem_assign(&mut self, rhs: Fix<Bits, Base, RExp>) {
557        self.bits %= rhs.bits;
558    }
559}
560
561impl<Bits, Base, Exp> RemAssign<Bits> for Fix<Bits, Base, Exp>
562where
563    Bits: RemAssign,
564{
565    fn rem_assign(&mut self, rhs: Bits) {
566        self.bits %= rhs;
567    }
568}
569
570// Checked arithmetic.
571
572impl<Bits, Base, Exp> CheckedAdd for Fix<Bits, Base, Exp>
573where
574    Bits: CheckedAdd,
575{
576    fn checked_add(&self, v: &Self) -> Option<Self> {
577        self.bits.checked_add(&v.bits).map(Self::new)
578    }
579}
580
581impl<Bits, Base, Exp> CheckedSub for Fix<Bits, Base, Exp>
582where
583    Bits: CheckedSub,
584{
585    fn checked_sub(&self, v: &Self) -> Option<Self> {
586        self.bits.checked_sub(&v.bits).map(Self::new)
587    }
588}
589
590impl<Bits, Base, Exp> Fix<Bits, Base, Exp>
591where
592    Self: CheckedSub,
593    Bits: Copy,
594{
595    #[must_use]
596    pub fn abs_diff(&self, v: &Self) -> Fix<Bits, Base, Exp> {
597        self.checked_sub(v).unwrap_or_else(|| *v - *self)
598    }
599}
600
601/// Adapts `CheckedMul` concept to this library with computed `Output` type.
602pub trait CheckedMulFix<Rhs> {
603    type Output;
604    fn checked_mul(&self, v: &Rhs) -> Option<Self::Output>;
605}
606
607impl<Bits, Base, LExp, RExp> CheckedMulFix<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
608where
609    Bits: CheckedMul,
610    LExp: Add<RExp>,
611{
612    type Output = Fix<Bits, Base, Sum<LExp, RExp>>;
613    fn checked_mul(&self, v: &Fix<Bits, Base, RExp>) -> Option<Self::Output> {
614        self.bits.checked_mul(&v.bits).map(Self::Output::new)
615    }
616}
617
618/// Adapts `CheckedDiv` to this library with computed `Output` type.
619pub trait CheckedDivFix<Rhs> {
620    type Output;
621    fn checked_div(&self, v: &Rhs) -> Option<Self::Output>;
622}
623
624impl<Bits, Base, LExp, RExp> CheckedDivFix<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
625where
626    Bits: CheckedDiv,
627    LExp: Sub<RExp>,
628{
629    type Output = Fix<Bits, Base, Diff<LExp, RExp>>;
630    fn checked_div(&self, v: &Fix<Bits, Base, RExp>) -> Option<Self::Output> {
631        self.bits.checked_div(&v.bits).map(Self::Output::new)
632    }
633}
634
635impl<Bits, Base, LExp, RExp> MulDiv<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
636where
637    Bits: MulDiv,
638{
639    type Output = Fix<<Bits as MulDiv>::Output, Base, LExp>;
640    fn mul_div_ceil(
641        self,
642        num: Fix<Bits, Base, RExp>,
643        denom: Fix<Bits, Base, RExp>,
644    ) -> Option<Self::Output> {
645        self.bits
646            .mul_div_ceil(num.bits, denom.bits)
647            .map(Self::Output::new)
648    }
649    fn mul_div_floor(
650        self,
651        num: Fix<Bits, Base, RExp>,
652        denom: Fix<Bits, Base, RExp>,
653    ) -> Option<Self::Output> {
654        self.bits
655            .mul_div_floor(num.bits, denom.bits)
656            .map(Self::Output::new)
657    }
658    fn mul_div_round(
659        self,
660        num: Fix<Bits, Base, RExp>,
661        denom: Fix<Bits, Base, RExp>,
662    ) -> Option<Self::Output> {
663        self.bits
664            .mul_div_round(num.bits, denom.bits)
665            .map(Self::Output::new)
666    }
667}
668
669// Saturating arithmetic.
670
671impl<Bits, Base, Exp> SaturatingAdd for Fix<Bits, Base, Exp>
672where
673    Bits: SaturatingAdd,
674{
675    fn saturating_add(&self, v: &Self) -> Self {
676        Self::new(self.bits.saturating_add(&v.bits))
677    }
678}
679
680impl<Bits, Base, Exp> SaturatingSub for Fix<Bits, Base, Exp>
681where
682    Bits: SaturatingSub,
683{
684    fn saturating_sub(&self, v: &Self) -> Self {
685        Self::new(self.bits.saturating_sub(&v.bits))
686    }
687}
688
689#[cfg(test)]
690mod tests {
691    #[cfg(feature = "alloc")]
692    use alloc::string::ToString;
693
694    use num_traits::{SaturatingAdd, SaturatingSub};
695    use typenum::{N3, P3, Z0};
696
697    use crate::aliases::decimal::{IFix64, UFix64};
698    use crate::aliases::si::{Kilo, Micro, Milli, Nano, Unit};
699    use crate::{CheckedAdd, CheckedDivFix, CheckedMulFix, CheckedSub, MulDiv};
700
701    #[test]
702    fn convert_milli_to_kilo() {
703        assert_eq!(Kilo::new(15), Milli::new(15_000_000).convert());
704    }
705
706    #[test]
707    fn convert_kilo_to_milli() {
708        assert_eq!(Milli::new(15_000_000), Kilo::new(15).convert());
709    }
710
711    #[test]
712    fn cmp() {
713        assert!(Kilo::new(1) < Kilo::new(2));
714    }
715
716    #[test]
717    fn neg() {
718        assert_eq!(Kilo::new(-1), -Kilo::new(1i32));
719    }
720
721    #[test]
722    fn add() {
723        assert_eq!(Kilo::new(3), Kilo::new(1) + Kilo::new(2));
724    }
725
726    #[test]
727    fn sub() {
728        assert_eq!(Kilo::new(1), Kilo::new(3) - Kilo::new(2));
729    }
730
731    #[test]
732    fn mul() {
733        assert_eq!(Unit::new(6), Kilo::new(2) * Milli::new(3));
734    }
735
736    #[test]
737    fn div() {
738        assert_eq!(Unit::new(3), Kilo::new(6) / Kilo::new(2));
739    }
740
741    #[test]
742    fn rem() {
743        assert_eq!(Kilo::new(1), Kilo::new(6) % Kilo::new(5));
744    }
745
746    #[test]
747    fn mul_bits() {
748        assert_eq!(Kilo::new(6), Kilo::new(2) * 3);
749    }
750
751    #[test]
752    fn div_bits() {
753        assert_eq!(Kilo::new(3), Kilo::new(6) / 2);
754    }
755
756    #[test]
757    fn rem_bits() {
758        assert_eq!(Kilo::new(1), Kilo::new(6) % 5);
759    }
760
761    #[test]
762    fn add_assign() {
763        let mut a = Kilo::new(1);
764        a += Kilo::new(2);
765        assert_eq!(Kilo::new(3), a);
766    }
767
768    #[test]
769    fn sub_assign() {
770        let mut a = Kilo::new(3);
771        a -= Kilo::new(2);
772        assert_eq!(Kilo::new(1), a);
773    }
774
775    #[test]
776    fn mul_assign_bits() {
777        let mut a = Kilo::new(2);
778        a *= 3;
779        assert_eq!(Kilo::new(6), a);
780    }
781
782    #[test]
783    fn div_assign_bits() {
784        let mut a = Kilo::new(6);
785        a /= 2;
786        assert_eq!(Kilo::new(3), a);
787    }
788
789    #[test]
790    fn rem_assign() {
791        let mut a = Kilo::new(6);
792        a %= Milli::new(5);
793        assert_eq!(Kilo::new(1), a);
794    }
795
796    #[test]
797    fn rem_assign_bits() {
798        let mut a = Kilo::new(6);
799        a %= 5;
800        assert_eq!(Kilo::new(1), a);
801    }
802
803    #[test]
804    fn checked_add_neg() {
805        let max = Kilo::new(u8::MAX);
806        let one = Kilo::new(1);
807        assert!(max.checked_add(&one).is_none());
808    }
809
810    #[test]
811    fn checked_add_pos() {
812        let forty = Kilo::new(40);
813        let two = Kilo::new(2);
814        assert_eq!(forty.checked_add(&two), Some(Kilo::new(42)));
815    }
816
817    #[test]
818    fn checked_sub_neg() {
819        let one = Kilo::new(1);
820        let max = Kilo::new(u8::MAX);
821        assert!(one.checked_sub(&max).is_none());
822    }
823
824    #[test]
825    fn checked_sub_pos() {
826        let fifty = Kilo::new(50);
827        let eight = Kilo::new(8);
828        assert_eq!(fifty.checked_sub(&eight), Some(Kilo::new(42)));
829    }
830
831    #[test]
832    fn checked_mul_neg() {
833        let fifty = Kilo::new(50);
834        let max = Kilo::new(u8::MAX);
835        assert!(fifty.checked_mul(&max).is_none());
836    }
837
838    #[test]
839    fn checked_mul_pos() {
840        let fifty = Kilo::new(50_u64);
841        assert_eq!(
842            fifty.checked_mul(&fifty).map(super::Fix::convert),
843            Some(Kilo::new(2_500_000_u64))
844        );
845    }
846
847    #[test]
848    fn checked_div_neg() {
849        let one = Unit::new(0);
850        assert!(one.checked_div(&one).is_none());
851    }
852
853    #[test]
854    fn checked_div_pos() {
855        let hundred = Kilo::new(100);
856        let five = Kilo::new(5);
857        assert_eq!(hundred.checked_div(&five), Some(Unit::new(20)));
858    }
859
860    #[test]
861    fn narrow_succeeds() {
862        let one = Milli::new(1000u128);
863        let mapped = one.narrow::<u64>();
864        assert_eq!(mapped, Some(Milli::new(1000u64)));
865    }
866
867    #[test]
868    fn narrow_fails() {
869        let one = Milli::new(1699u64);
870        let mapped = one.narrow::<u8>();
871        assert_eq!(mapped, None);
872    }
873
874    #[test]
875    fn widen_succeeds() {
876        let one = Milli::new(1_340_191u64);
877        let mapped = one.widen::<u128>();
878        assert_eq!(mapped, Milli::new(1_340_191_u128));
879    }
880
881    #[test]
882    fn mul_div_ceil() {
883        let start = Milli::new(313_459u64);
884        let mul = Milli::new(1200u64);
885        let div = Milli::new(2450u64);
886        assert_eq!(start.mul_div_ceil(mul, div), Some(Milli::new(153_531)));
887    }
888
889    #[test]
890    fn mul_div_ceil_unit() {
891        let start = Milli::new(31_345_934u64);
892        let mul = Milli::new(1000u64);
893        let div = Milli::new(2000u64);
894        assert_eq!(
895            start.mul_div_ceil(mul, div),
896            Some(Milli::new(15_672_967_u64))
897        );
898    }
899
900    #[test]
901    fn mul_div_floor() {
902        let start = Milli::new(69_693u64);
903        let mul = Milli::new(5_192u64);
904        let div = Milli::new(190u64);
905        assert_eq!(
906            start.mul_div_floor(mul, div),
907            Some(Milli::new(1_904_452_u64))
908        );
909    }
910
911    #[test]
912    fn mul_div_floor_unit() {
913        let start = Milli::new(69_693u64);
914        let mul = Milli::new(1000u64);
915        let div = Milli::new(9u64);
916        assert_eq!(
917            start.mul_div_floor(mul, div),
918            Some(Milli::new(7_743_666_u64))
919        );
920    }
921
922    #[test]
923    fn mul_div_round() {
924        let start = Milli::new(1892u64);
925        let mul = Milli::new(3222u64);
926        let div = Milli::new(9999u64);
927        assert_eq!(start.mul_div_round(mul, div), Some(Milli::new(610u64)));
928    }
929
930    #[test]
931    fn mul_div_round_unit() {
932        let start = Milli::new(1892u64);
933        let mul = Milli::new(1000u64);
934        let div = Milli::new(322u64);
935        assert_eq!(start.mul_div_round(mul, div), Some(Milli::new(5876u64)));
936    }
937
938    #[test]
939    fn abs_diff() {
940        let start = Milli::new(u128::MIN);
941        let end = Milli::new(u128::MAX);
942        assert_eq!(start.abs_diff(&end), end);
943    }
944
945    #[test]
946    fn constant() {
947        assert_eq!(Kilo::constant(69u64), Kilo::new(69u64));
948    }
949
950    #[test]
951    fn saturating_sub() {
952        let zero = Kilo::constant(0);
953        let result = zero.saturating_sub(&Kilo::new(69u64));
954        assert_eq!(zero, result);
955    }
956
957    #[test]
958    fn saturating_add() {
959        let max = Kilo::new(u64::MAX);
960        let result = max.saturating_add(&Kilo::new(69u64));
961        assert_eq!(max, result);
962    }
963
964    #[test]
965    fn zero_is_zero() {
966        assert_eq!(Kilo::<u64>::zero().bits, 0);
967        assert_eq!(Milli::<u64>::zero().bits, 0);
968        assert_eq!(Nano::<u64>::zero().bits, 0);
969    }
970
971    #[test]
972    fn one_is_correct() {
973        assert_eq!(Milli::<u64>::one().bits, 1_000);
974        assert_eq!(Micro::<u64>::one().bits, 1_000_000);
975        assert_eq!(Nano::<u64>::one().bits, 1_000_000_000);
976    }
977
978    #[test]
979    fn checked_convert_upconvert() {
980        assert_eq!(
981            Milli::new(5u64).checked_convert(),
982            Some(Micro::new(5_000u64)),
983        );
984    }
985
986    #[test]
987    fn checked_convert_downconvert() {
988        assert_eq!(
989            Micro::new(5_000u64).checked_convert(),
990            Some(Milli::new(5u64)),
991        );
992    }
993
994    #[test]
995    fn checked_convert_identity() {
996        assert_eq!(Milli::new(42u64).checked_convert(), Some(Milli::new(42u64)),);
997    }
998
999    #[test]
1000    fn checked_convert_overflow() {
1001        assert_eq!(Milli::new(u64::MAX).checked_convert::<typenum::N9>(), None,);
1002    }
1003
1004    #[test]
1005    fn checked_convert_matches_convert() {
1006        let value = Milli::new(15u64);
1007        assert_eq!(
1008            value.checked_convert::<typenum::N6>(),
1009            Some(value.convert::<typenum::N6>()),
1010        );
1011    }
1012
1013    #[test]
1014    fn checked_convert_ceil_downconvert_rounds_up() {
1015        assert_eq!(
1016            Micro::new(5_001u64).checked_convert_ceil(),
1017            Some(Milli::new(6u64)),
1018        );
1019    }
1020
1021    #[test]
1022    fn checked_convert_ceil_exact_matches_floor() {
1023        assert_eq!(
1024            Micro::new(5_000u64).checked_convert_ceil(),
1025            Some(Milli::new(5u64)),
1026        );
1027    }
1028
1029    #[test]
1030    fn checked_convert_ceil_upconvert() {
1031        assert_eq!(
1032            Milli::new(5u64).checked_convert_ceil(),
1033            Some(Micro::new(5_000u64)),
1034        );
1035    }
1036
1037    #[test]
1038    fn checked_convert_ceil_overflow() {
1039        assert_eq!(
1040            Milli::new(u64::MAX).checked_convert_ceil::<typenum::N9>(),
1041            None,
1042        );
1043    }
1044
1045    #[cfg(feature = "alloc")]
1046    #[test]
1047    fn display_negative_exp() {
1048        assert_eq!(UFix64::<N3>::new(1_234).to_string(), "1.234");
1049        assert_eq!(UFix64::<N3>::new(1).to_string(), "0.001");
1050        assert_eq!(UFix64::<N3>::new(0).to_string(), "0.000");
1051    }
1052
1053    #[cfg(feature = "alloc")]
1054    #[test]
1055    fn display_negative_exp_signed() {
1056        assert_eq!(IFix64::<N3>::new(-1_234).to_string(), "-1.234");
1057        assert_eq!(IFix64::<N3>::new(-1).to_string(), "-0.001");
1058    }
1059
1060    #[cfg(feature = "alloc")]
1061    #[test]
1062    fn display_positive_exp() {
1063        assert_eq!(UFix64::<P3>::new(5).to_string(), "5000");
1064    }
1065
1066    #[cfg(feature = "alloc")]
1067    #[test]
1068    fn display_zero_exp() {
1069        assert_eq!(UFix64::<Z0>::new(42).to_string(), "42");
1070    }
1071}