1#![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
108pub struct Fix<Bits, Base, Exp> {
136 pub bits: Bits,
138
139 marker: PhantomData<(Base, Exp)>,
140}
141
142impl<Bits, Base, Exp> Fix<Bits, Base, Exp> {
143 pub fn new(bits: Bits) -> Self {
153 Fix {
154 bits,
155 marker: PhantomData,
156 }
157 }
158
159 pub const fn constant(bits: Bits) -> Self {
161 Fix {
162 bits,
163 marker: PhantomData,
164 }
165 }
166
167 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 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 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 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
239pub trait FromUnsigned {
246 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
275pub trait Pow {
280 #[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
309impl<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
392impl<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
422impl<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
570impl<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
601pub 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
618pub 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
669impl<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}