1pub extern crate muldiv;
68pub extern crate num_traits;
69#[cfg(feature = "typed-floats")]
70pub extern crate typed_floats;
71pub extern crate typenum;
72
73pub mod aliases;
74pub mod fix_value;
75pub mod prelude;
76pub mod util;
77
78use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
79use core::fmt::{Debug, Display, Error, Formatter};
80use core::hash::{Hash, Hasher};
81use core::marker::PhantomData;
82use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
83use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
84
85use muldiv::MulDiv;
86use num_traits::{
87 CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, ConstZero, SaturatingAdd, SaturatingSub,
88};
89use paste::paste;
90use typenum::consts::{U10, Z0};
91use typenum::marker_traits::{Bit, Integer, Unsigned};
92use typenum::operator_aliases::{AbsVal, Diff, Le, Sum};
93use typenum::type_operators::{Abs, IsLess};
94
95pub struct Fix<Bits, Base, Exp> {
123 pub bits: Bits,
125
126 marker: PhantomData<(Base, Exp)>,
127}
128
129impl<Bits, Base, Exp> Fix<Bits, Base, Exp> {
130 pub fn new(bits: Bits) -> Self {
140 Fix {
141 bits,
142 marker: PhantomData,
143 }
144 }
145
146 pub const fn constant(bits: Bits) -> Self {
148 Fix {
149 bits,
150 marker: PhantomData,
151 }
152 }
153
154 pub fn convert<ToExp>(self) -> Fix<Bits, Base, ToExp>
166 where
167 Bits: FromUnsigned + Pow + Mul<Output = Bits> + Div<Output = Bits>,
168 Base: Unsigned,
169 Exp: Sub<ToExp>,
170 Diff<Exp, ToExp>: Abs + IsLess<Z0>,
171 AbsVal<Diff<Exp, ToExp>>: Integer,
172 {
173 let base = Bits::from_unsigned::<Base>();
174 let diff = AbsVal::<Diff<Exp, ToExp>>::to_i32();
175 let inverse = Le::<Diff<Exp, ToExp>, Z0>::to_bool();
176
177 let ratio = base.pow(diff.unsigned_abs());
180
181 if inverse {
182 Fix::new(self.bits / ratio)
183 } else {
184 Fix::new(self.bits * ratio)
185 }
186 }
187
188 pub fn widen<ToBits>(self) -> Fix<ToBits, Base, Exp>
200 where
201 ToBits: From<Bits>,
202 {
203 Fix::<ToBits, Base, Exp>::new(self.bits.into())
204 }
205
206 pub fn narrow<ToBits>(self) -> Option<Fix<ToBits, Base, Exp>>
219 where
220 ToBits: TryFrom<Bits>,
221 {
222 self.bits.try_into().ok().map(Fix::<ToBits, Base, Exp>::new)
223 }
224}
225
226pub trait FromUnsigned {
233 fn from_unsigned<U>() -> Self
235 where
236 U: Unsigned;
237}
238
239macro_rules! impl_from_unsigned {
240 ($ty:ident) => {
241 impl FromUnsigned for $ty {
242 fn from_unsigned<U: Unsigned>() -> Self {
243 paste! { U::[<to_$ty>]() }
244 }
245 }
246 };
247}
248
249impl_from_unsigned!(u8);
250impl_from_unsigned!(u16);
251impl_from_unsigned!(u32);
252impl_from_unsigned!(u64);
253impl_from_unsigned!(u128);
254impl_from_unsigned!(usize);
255impl_from_unsigned!(i8);
256impl_from_unsigned!(i16);
257impl_from_unsigned!(i32);
258impl_from_unsigned!(i64);
259impl_from_unsigned!(i128);
260impl_from_unsigned!(isize);
261
262pub trait Pow {
267 #[must_use]
269 fn pow(self, exp: u32) -> Self;
270}
271
272macro_rules! impl_pow {
273 ($ty:ident) => {
274 impl Pow for $ty {
275 #[inline]
276 fn pow(self, exp: u32) -> Self {
277 self.pow(exp)
278 }
279 }
280 };
281}
282
283impl_pow!(u8);
284impl_pow!(u16);
285impl_pow!(u32);
286impl_pow!(u64);
287impl_pow!(u128);
288impl_pow!(usize);
289impl_pow!(i8);
290impl_pow!(i16);
291impl_pow!(i32);
292impl_pow!(i64);
293impl_pow!(i128);
294impl_pow!(isize);
295
296impl<Bits, Base, Exp> Copy for Fix<Bits, Base, Exp> where Bits: Copy {}
299
300impl<Bits, Base, Exp> Clone for Fix<Bits, Base, Exp>
301where
302 Bits: Clone,
303{
304 fn clone(&self) -> Self {
305 Self::new(self.bits.clone())
306 }
307}
308
309impl<Bits, Base, Exp> Default for Fix<Bits, Base, Exp>
310where
311 Bits: Default,
312{
313 fn default() -> Self {
314 Self::new(Bits::default())
315 }
316}
317
318impl<Bits, Base, Exp> Fix<Bits, Base, Exp>
319where
320 Bits: ConstZero,
321{
322 #[must_use]
323 pub const fn zero() -> Self {
324 Self::constant(Bits::ZERO)
325 }
326}
327
328impl<Bits, Base, Exp> Hash for Fix<Bits, Base, Exp>
329where
330 Bits: Hash,
331{
332 fn hash<H>(&self, state: &mut H)
333 where
334 H: Hasher,
335 {
336 self.bits.hash(state);
337 }
338}
339
340impl<Bits, Base, Exp> Debug for Fix<Bits, Base, Exp>
341where
342 Bits: Debug,
343 Base: Unsigned,
344 Exp: Integer,
345{
346 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
347 write!(f, "{:?}x{}^{}", self.bits, Base::to_u64(), Exp::to_i64())
348 }
349}
350
351impl<Bits, Exp> Display for Fix<Bits, U10, Exp>
352where
353 Bits: Display,
354 Exp: Integer,
355{
356 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
357 let exp = Exp::to_i32();
358 let decimals = usize::try_from(exp.unsigned_abs()).map_err(|_| Error)?;
359 let raw = self.bits.to_string();
360 let (sign, digits) = raw
361 .strip_prefix('-')
362 .map_or(("", raw.as_str()), |d| ("-", d));
363
364 match exp {
365 0.. => write!(f, "{sign}{digits}{}", "0".repeat(decimals)),
366 _ if digits.len() > decimals => {
367 let (integer, fraction) = digits.split_at(digits.len() - decimals);
368 write!(f, "{sign}{integer}.{fraction}")
369 }
370 _ => {
371 let padding = "0".repeat(decimals - digits.len());
372 write!(f, "{sign}0.{padding}{digits}")
373 }
374 }
375 }
376}
377
378impl<Bits, Base, Exp> Eq for Fix<Bits, Base, Exp> where Bits: Eq {}
381impl<Bits, Base, Exp> PartialEq for Fix<Bits, Base, Exp>
382where
383 Bits: PartialEq,
384{
385 fn eq(&self, rhs: &Self) -> bool {
386 self.bits == rhs.bits
387 }
388}
389
390impl<Bits, Base, Exp> PartialOrd for Fix<Bits, Base, Exp>
391where
392 Bits: PartialOrd,
393{
394 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
395 self.bits.partial_cmp(&rhs.bits)
396 }
397}
398
399impl<Bits, Base, Exp> Ord for Fix<Bits, Base, Exp>
400where
401 Bits: Ord,
402{
403 fn cmp(&self, rhs: &Self) -> Ordering {
404 self.bits.cmp(&rhs.bits)
405 }
406}
407
408impl<Bits, Base, Exp> Neg for Fix<Bits, Base, Exp>
411where
412 Bits: Neg<Output = Bits>,
413{
414 type Output = Self;
415 fn neg(self) -> Self {
416 Self::new(-self.bits)
417 }
418}
419
420impl<Bits, Base, Exp> Add for Fix<Bits, Base, Exp>
421where
422 Bits: Add<Output = Bits>,
423{
424 type Output = Self;
425 fn add(self, rhs: Self) -> Self {
426 Self::new(self.bits + rhs.bits)
427 }
428}
429
430impl<Bits, Base, Exp> Sub for Fix<Bits, Base, Exp>
431where
432 Bits: Sub<Output = Bits>,
433{
434 type Output = Self;
435 fn sub(self, rhs: Self) -> Self {
436 Self::new(self.bits - rhs.bits)
437 }
438}
439
440impl<Bits, Base, LExp, RExp> Mul<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
441where
442 Bits: Mul<Output = Bits>,
443 LExp: Add<RExp>,
444{
445 type Output = Fix<Bits, Base, Sum<LExp, RExp>>;
446 fn mul(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
447 Self::Output::new(self.bits * rhs.bits)
448 }
449}
450
451impl<Bits, Base, LExp, RExp> Div<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
452where
453 Bits: Div<Output = Bits>,
454 LExp: Sub<RExp>,
455{
456 type Output = Fix<Bits, Base, Diff<LExp, RExp>>;
457 fn div(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
458 Self::Output::new(self.bits / rhs.bits)
459 }
460}
461
462impl<Bits, Base, Exp> Rem for Fix<Bits, Base, Exp>
463where
464 Bits: Rem<Output = Bits>,
465{
466 type Output = Self;
467 fn rem(self, rhs: Self) -> Self {
468 Self::new(self.bits % rhs.bits)
469 }
470}
471
472impl<Bits, Base, Exp> Mul<Bits> for Fix<Bits, Base, Exp>
473where
474 Bits: Mul<Output = Bits>,
475{
476 type Output = Self;
477 fn mul(self, rhs: Bits) -> Self {
478 Self::new(self.bits * rhs)
479 }
480}
481
482impl<Bits, Base, Exp> Div<Bits> for Fix<Bits, Base, Exp>
483where
484 Bits: Div<Output = Bits>,
485{
486 type Output = Self;
487 fn div(self, rhs: Bits) -> Self {
488 Self::new(self.bits / rhs)
489 }
490}
491
492impl<Bits, Base, Exp> Rem<Bits> for Fix<Bits, Base, Exp>
493where
494 Bits: Rem<Output = Bits>,
495{
496 type Output = Self;
497 fn rem(self, rhs: Bits) -> Self {
498 Self::new(self.bits % rhs)
499 }
500}
501
502impl<Bits, Base, Exp> AddAssign for Fix<Bits, Base, Exp>
503where
504 Bits: AddAssign,
505{
506 fn add_assign(&mut self, rhs: Self) {
507 self.bits += rhs.bits;
508 }
509}
510
511impl<Bits, Base, Exp> SubAssign for Fix<Bits, Base, Exp>
512where
513 Bits: SubAssign,
514{
515 fn sub_assign(&mut self, rhs: Self) {
516 self.bits -= rhs.bits;
517 }
518}
519
520impl<Bits, Base, Exp> MulAssign<Bits> for Fix<Bits, Base, Exp>
521where
522 Bits: MulAssign,
523{
524 fn mul_assign(&mut self, rhs: Bits) {
525 self.bits *= rhs;
526 }
527}
528
529impl<Bits, Base, Exp> DivAssign<Bits> for Fix<Bits, Base, Exp>
530where
531 Bits: DivAssign,
532{
533 fn div_assign(&mut self, rhs: Bits) {
534 self.bits /= rhs;
535 }
536}
537
538impl<Bits, Base, LExp, RExp> RemAssign<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
539where
540 Bits: RemAssign,
541{
542 fn rem_assign(&mut self, rhs: Fix<Bits, Base, RExp>) {
543 self.bits %= rhs.bits;
544 }
545}
546
547impl<Bits, Base, Exp> RemAssign<Bits> for Fix<Bits, Base, Exp>
548where
549 Bits: RemAssign,
550{
551 fn rem_assign(&mut self, rhs: Bits) {
552 self.bits %= rhs;
553 }
554}
555
556impl<Bits, Base, Exp> CheckedAdd for Fix<Bits, Base, Exp>
559where
560 Bits: CheckedAdd,
561{
562 fn checked_add(&self, v: &Self) -> Option<Self> {
563 self.bits.checked_add(&v.bits).map(Self::new)
564 }
565}
566
567impl<Bits, Base, Exp> CheckedSub for Fix<Bits, Base, Exp>
568where
569 Bits: CheckedSub,
570{
571 fn checked_sub(&self, v: &Self) -> Option<Self> {
572 self.bits.checked_sub(&v.bits).map(Self::new)
573 }
574}
575
576impl<Bits, Base, Exp> Fix<Bits, Base, Exp>
577where
578 Self: CheckedSub,
579 Bits: Copy,
580{
581 #[must_use]
582 pub fn abs_diff(&self, v: &Self) -> Fix<Bits, Base, Exp> {
583 self.checked_sub(v).unwrap_or_else(|| *v - *self)
584 }
585}
586
587pub trait CheckedMulFix<Rhs> {
589 type Output;
590 fn checked_mul(&self, v: &Rhs) -> Option<Self::Output>;
591}
592
593impl<Bits, Base, LExp, RExp> CheckedMulFix<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
594where
595 Bits: CheckedMul,
596 LExp: Add<RExp>,
597{
598 type Output = Fix<Bits, Base, Sum<LExp, RExp>>;
599 fn checked_mul(&self, v: &Fix<Bits, Base, RExp>) -> Option<Self::Output> {
600 self.bits.checked_mul(&v.bits).map(Self::Output::new)
601 }
602}
603
604pub trait CheckedDivFix<Rhs> {
606 type Output;
607 fn checked_div(&self, v: &Rhs) -> Option<Self::Output>;
608}
609
610impl<Bits, Base, LExp, RExp> CheckedDivFix<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
611where
612 Bits: CheckedDiv,
613 LExp: Sub<RExp>,
614{
615 type Output = Fix<Bits, Base, Diff<LExp, RExp>>;
616 fn checked_div(&self, v: &Fix<Bits, Base, RExp>) -> Option<Self::Output> {
617 self.bits.checked_div(&v.bits).map(Self::Output::new)
618 }
619}
620
621impl<Bits, Base, LExp, RExp> MulDiv<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
622where
623 Bits: MulDiv,
624{
625 type Output = Fix<<Bits as MulDiv>::Output, Base, LExp>;
626 fn mul_div_ceil(
627 self,
628 num: Fix<Bits, Base, RExp>,
629 denom: Fix<Bits, Base, RExp>,
630 ) -> Option<Self::Output> {
631 self.bits
632 .mul_div_ceil(num.bits, denom.bits)
633 .map(Self::Output::new)
634 }
635 fn mul_div_floor(
636 self,
637 num: Fix<Bits, Base, RExp>,
638 denom: Fix<Bits, Base, RExp>,
639 ) -> Option<Self::Output> {
640 self.bits
641 .mul_div_floor(num.bits, denom.bits)
642 .map(Self::Output::new)
643 }
644 fn mul_div_round(
645 self,
646 num: Fix<Bits, Base, RExp>,
647 denom: Fix<Bits, Base, RExp>,
648 ) -> Option<Self::Output> {
649 self.bits
650 .mul_div_round(num.bits, denom.bits)
651 .map(Self::Output::new)
652 }
653}
654
655impl<Bits, Base, Exp> SaturatingAdd for Fix<Bits, Base, Exp>
658where
659 Bits: SaturatingAdd,
660{
661 fn saturating_add(&self, v: &Self) -> Self {
662 Self::new(self.bits.saturating_add(&v.bits))
663 }
664}
665
666impl<Bits, Base, Exp> SaturatingSub for Fix<Bits, Base, Exp>
667where
668 Bits: SaturatingSub,
669{
670 fn saturating_sub(&self, v: &Self) -> Self {
671 Self::new(self.bits.saturating_sub(&v.bits))
672 }
673}
674
675#[cfg(test)]
676mod tests {
677 use num_traits::{SaturatingAdd, SaturatingSub};
678 use typenum::{N3, P3, Z0};
679
680 use crate::aliases::decimal::{IFix64, UFix64};
681 use crate::aliases::si::{Kilo, Micro, Milli, Nano, Unit};
682 use crate::{CheckedAdd, CheckedDivFix, CheckedMulFix, CheckedSub, MulDiv};
683
684 #[test]
685 fn convert_milli_to_kilo() {
686 assert_eq!(Kilo::new(15), Milli::new(15_000_000).convert());
687 }
688
689 #[test]
690 fn convert_kilo_to_milli() {
691 assert_eq!(Milli::new(15_000_000), Kilo::new(15).convert());
692 }
693
694 #[test]
695 fn cmp() {
696 assert!(Kilo::new(1) < Kilo::new(2));
697 }
698
699 #[test]
700 fn neg() {
701 assert_eq!(Kilo::new(-1), -Kilo::new(1i32));
702 }
703
704 #[test]
705 fn add() {
706 assert_eq!(Kilo::new(3), Kilo::new(1) + Kilo::new(2));
707 }
708
709 #[test]
710 fn sub() {
711 assert_eq!(Kilo::new(1), Kilo::new(3) - Kilo::new(2));
712 }
713
714 #[test]
715 fn mul() {
716 assert_eq!(Unit::new(6), Kilo::new(2) * Milli::new(3));
717 }
718
719 #[test]
720 fn div() {
721 assert_eq!(Unit::new(3), Kilo::new(6) / Kilo::new(2));
722 }
723
724 #[test]
725 fn rem() {
726 assert_eq!(Kilo::new(1), Kilo::new(6) % Kilo::new(5));
727 }
728
729 #[test]
730 fn mul_bits() {
731 assert_eq!(Kilo::new(6), Kilo::new(2) * 3);
732 }
733
734 #[test]
735 fn div_bits() {
736 assert_eq!(Kilo::new(3), Kilo::new(6) / 2);
737 }
738
739 #[test]
740 fn rem_bits() {
741 assert_eq!(Kilo::new(1), Kilo::new(6) % 5);
742 }
743
744 #[test]
745 fn add_assign() {
746 let mut a = Kilo::new(1);
747 a += Kilo::new(2);
748 assert_eq!(Kilo::new(3), a);
749 }
750
751 #[test]
752 fn sub_assign() {
753 let mut a = Kilo::new(3);
754 a -= Kilo::new(2);
755 assert_eq!(Kilo::new(1), a);
756 }
757
758 #[test]
759 fn mul_assign_bits() {
760 let mut a = Kilo::new(2);
761 a *= 3;
762 assert_eq!(Kilo::new(6), a);
763 }
764
765 #[test]
766 fn div_assign_bits() {
767 let mut a = Kilo::new(6);
768 a /= 2;
769 assert_eq!(Kilo::new(3), a);
770 }
771
772 #[test]
773 fn rem_assign() {
774 let mut a = Kilo::new(6);
775 a %= Milli::new(5);
776 assert_eq!(Kilo::new(1), a);
777 }
778
779 #[test]
780 fn rem_assign_bits() {
781 let mut a = Kilo::new(6);
782 a %= 5;
783 assert_eq!(Kilo::new(1), a);
784 }
785
786 #[test]
787 fn checked_add_neg() {
788 let max = Kilo::new(u8::MAX);
789 let one = Kilo::new(1);
790 assert!(max.checked_add(&one).is_none());
791 }
792
793 #[test]
794 fn checked_add_pos() {
795 let forty = Kilo::new(40);
796 let two = Kilo::new(2);
797 assert_eq!(forty.checked_add(&two), Some(Kilo::new(42)));
798 }
799
800 #[test]
801 fn checked_sub_neg() {
802 let one = Kilo::new(1);
803 let max = Kilo::new(u8::MAX);
804 assert!(one.checked_sub(&max).is_none());
805 }
806
807 #[test]
808 fn checked_sub_pos() {
809 let fifty = Kilo::new(50);
810 let eight = Kilo::new(8);
811 assert_eq!(fifty.checked_sub(&eight), Some(Kilo::new(42)));
812 }
813
814 #[test]
815 fn checked_mul_neg() {
816 let fifty = Kilo::new(50);
817 let max = Kilo::new(u8::MAX);
818 assert!(fifty.checked_mul(&max).is_none());
819 }
820
821 #[test]
822 fn checked_mul_pos() {
823 let fifty = Kilo::new(50_u64);
824 assert_eq!(
825 fifty.checked_mul(&fifty).map(super::Fix::convert),
826 Some(Kilo::new(2_500_000_u64))
827 );
828 }
829
830 #[test]
831 fn checked_div_neg() {
832 let one = Unit::new(0);
833 assert!(one.checked_div(&one).is_none());
834 }
835
836 #[test]
837 fn checked_div_pos() {
838 let hundred = Kilo::new(100);
839 let five = Kilo::new(5);
840 assert_eq!(hundred.checked_div(&five), Some(Unit::new(20)));
841 }
842
843 #[test]
844 fn narrow_succeeds() {
845 let one = Milli::new(1000u128);
846 let mapped = one.narrow::<u64>();
847 assert_eq!(mapped, Some(Milli::new(1000u64)));
848 }
849
850 #[test]
851 fn narrow_fails() {
852 let one = Milli::new(1699u64);
853 let mapped = one.narrow::<u8>();
854 assert_eq!(mapped, None);
855 }
856
857 #[test]
858 fn widen_succeeds() {
859 let one = Milli::new(1_340_191u64);
860 let mapped = one.widen::<u128>();
861 assert_eq!(mapped, Milli::new(1_340_191_u128));
862 }
863
864 #[test]
865 fn mul_div_ceil() {
866 let start = Milli::new(313_459u64);
867 let mul = Milli::new(1200u64);
868 let div = Milli::new(2450u64);
869 assert_eq!(start.mul_div_ceil(mul, div), Some(Milli::new(153_531)));
870 }
871
872 #[test]
873 fn mul_div_ceil_unit() {
874 let start = Milli::new(31_345_934u64);
875 let mul = Milli::new(1000u64);
876 let div = Milli::new(2000u64);
877 assert_eq!(
878 start.mul_div_ceil(mul, div),
879 Some(Milli::new(15_672_967_u64))
880 );
881 }
882
883 #[test]
884 fn mul_div_floor() {
885 let start = Milli::new(69_693u64);
886 let mul = Milli::new(5_192u64);
887 let div = Milli::new(190u64);
888 assert_eq!(
889 start.mul_div_floor(mul, div),
890 Some(Milli::new(1_904_452_u64))
891 );
892 }
893
894 #[test]
895 fn mul_div_floor_unit() {
896 let start = Milli::new(69_693u64);
897 let mul = Milli::new(1000u64);
898 let div = Milli::new(9u64);
899 assert_eq!(
900 start.mul_div_floor(mul, div),
901 Some(Milli::new(7_743_666_u64))
902 );
903 }
904
905 #[test]
906 fn mul_div_round() {
907 let start = Milli::new(1892u64);
908 let mul = Milli::new(3222u64);
909 let div = Milli::new(9999u64);
910 assert_eq!(start.mul_div_round(mul, div), Some(Milli::new(610u64)));
911 }
912
913 #[test]
914 fn mul_div_round_unit() {
915 let start = Milli::new(1892u64);
916 let mul = Milli::new(1000u64);
917 let div = Milli::new(322u64);
918 assert_eq!(start.mul_div_round(mul, div), Some(Milli::new(5876u64)));
919 }
920
921 #[test]
922 fn abs_diff() {
923 let start = Milli::new(u128::MIN);
924 let end = Milli::new(u128::MAX);
925 assert_eq!(start.abs_diff(&end), end);
926 }
927
928 #[test]
929 fn constant() {
930 assert_eq!(Kilo::constant(69u64), Kilo::new(69u64));
931 }
932
933 #[test]
934 fn saturating_sub() {
935 let zero = Kilo::constant(0);
936 let result = zero.saturating_sub(&Kilo::new(69u64));
937 assert_eq!(zero, result);
938 }
939
940 #[test]
941 fn saturating_add() {
942 let max = Kilo::new(u64::MAX);
943 let result = max.saturating_add(&Kilo::new(69u64));
944 assert_eq!(max, result);
945 }
946
947 #[test]
948 fn zero_is_zero() {
949 assert_eq!(Kilo::<u64>::zero().bits, 0);
950 assert_eq!(Milli::<u64>::zero().bits, 0);
951 assert_eq!(Nano::<u64>::zero().bits, 0);
952 }
953
954 #[test]
955 fn one_is_correct() {
956 assert_eq!(Milli::<u64>::one().bits, 1_000);
957 assert_eq!(Micro::<u64>::one().bits, 1_000_000);
958 assert_eq!(Nano::<u64>::one().bits, 1_000_000_000);
959 }
960
961 #[test]
962 fn checked_convert_upconvert() {
963 assert_eq!(
964 Milli::new(5u64).checked_convert(),
965 Some(Micro::new(5_000u64)),
966 );
967 }
968
969 #[test]
970 fn checked_convert_downconvert() {
971 assert_eq!(
972 Micro::new(5_000u64).checked_convert(),
973 Some(Milli::new(5u64)),
974 );
975 }
976
977 #[test]
978 fn checked_convert_identity() {
979 assert_eq!(Milli::new(42u64).checked_convert(), Some(Milli::new(42u64)),);
980 }
981
982 #[test]
983 fn checked_convert_overflow() {
984 assert_eq!(Milli::new(u64::MAX).checked_convert::<typenum::N9>(), None,);
985 }
986
987 #[test]
988 fn checked_convert_matches_convert() {
989 let value = Milli::new(15u64);
990 assert_eq!(
991 value.checked_convert::<typenum::N6>(),
992 Some(value.convert::<typenum::N6>()),
993 );
994 }
995
996 #[test]
997 fn checked_convert_ceil_downconvert_rounds_up() {
998 assert_eq!(
999 Micro::new(5_001u64).checked_convert_ceil(),
1000 Some(Milli::new(6u64)),
1001 );
1002 }
1003
1004 #[test]
1005 fn checked_convert_ceil_exact_matches_floor() {
1006 assert_eq!(
1007 Micro::new(5_000u64).checked_convert_ceil(),
1008 Some(Milli::new(5u64)),
1009 );
1010 }
1011
1012 #[test]
1013 fn checked_convert_ceil_upconvert() {
1014 assert_eq!(
1015 Milli::new(5u64).checked_convert_ceil(),
1016 Some(Micro::new(5_000u64)),
1017 );
1018 }
1019
1020 #[test]
1021 fn checked_convert_ceil_overflow() {
1022 assert_eq!(
1023 Milli::new(u64::MAX).checked_convert_ceil::<typenum::N9>(),
1024 None,
1025 );
1026 }
1027
1028 #[test]
1029 fn display_negative_exp() {
1030 assert_eq!(UFix64::<N3>::new(1_234).to_string(), "1.234");
1031 assert_eq!(UFix64::<N3>::new(1).to_string(), "0.001");
1032 assert_eq!(UFix64::<N3>::new(0).to_string(), "0.000");
1033 }
1034
1035 #[test]
1036 fn display_negative_exp_signed() {
1037 assert_eq!(IFix64::<N3>::new(-1_234).to_string(), "-1.234");
1038 assert_eq!(IFix64::<N3>::new(-1).to_string(), "-0.001");
1039 }
1040
1041 #[test]
1042 fn display_positive_exp() {
1043 assert_eq!(UFix64::<P3>::new(5).to_string(), "5000");
1044 }
1045
1046 #[test]
1047 fn display_zero_exp() {
1048 assert_eq!(UFix64::<Z0>::new(42).to_string(), "42");
1049 }
1050}