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