[go: up one dir, main page]

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//! # `i128` support
66//!
67//! Support for `u128` and `i128` can be enabled on nightly Rust through the `i128` Cargo feature.
68
69#![no_std]
70
71#![cfg_attr(feature = "i128", feature(i128_type))]
72
73pub extern crate typenum;
74
75/// Type aliases.
76pub mod aliases;
77
78use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
79use core::fmt::{Debug, Error, Formatter};
80use core::hash::{Hash, Hasher};
81use core::marker::PhantomData;
82use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
83use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
84
85use typenum::consts::Z0;
86use typenum::marker_traits::{Bit, Integer, Unsigned};
87use typenum::operator_aliases::{AbsVal, Diff, Le, Sum};
88use typenum::type_operators::{Abs, IsLess};
89
90/// Fixed-point number representing _Bits × Base <sup>Exp</sup>_.
91///
92/// - `Bits` is an integer primitive type, or any type which can be created from a type-level
93///   integer and exponentiated.
94/// - `Base` is an [`Unsigned`] type-level integer.
95/// - `Exp` is a signed type-level [`Integer`].
96///
97/// [`Unsigned`]: ../typenum/marker_traits/trait.Unsigned.html
98/// [`Integer`]: ../typenum/marker_traits/trait.Integer.html
99///
100/// # Summary of operations
101///
102/// Lower case variables represent values of _Bits_. Upper case _B_ and _E_ represent type-level
103/// integers _Base_ and _Exp_, respectively.
104///
105/// - _−(x B<sup>E</sup>) = (−x) B<sup>E</sup>_
106/// - _(x B<sup>E</sup>) + (y B<sup>E</sup>) = (x + y) B<sup>E</sup>_
107/// - _(x B<sup>E</sup>) − (y B<sup>E</sup>) = (x − y) B<sup>E</sup>_
108/// - _(x B<sup>E<sub>x</sub></sup>) × (y B<sup>E<sub>y</sub></sup>) =
109///   (x × y) B<sup>E<sub>x</sub> + E<sub>y</sub></sup>_
110/// - _(x B<sup>E<sub>x</sub></sup>) ÷ (y B<sup>E<sub>y</sub></sup>) =
111///   (x ÷ y) B<sup>E<sub>x</sub> − E<sub>y</sub></sup>_
112/// - _(x B<sup>E<sub>x</sub></sup>) % (y B<sup>E<sub>y</sub></sup>) =
113///   (x % y) B<sup>E<sub>x</sub></sup>_
114/// - _(x B<sup>E</sup>) × y = (x × y) B<sup>E</sup>_
115/// - _(x B<sup>E</sup>) ÷ y = (x ÷ y) B<sup>E</sup>_
116/// - _(x B<sup>E</sup>) % y = (x % y) B<sup>E</sup>_
117pub struct Fix<Bits, Base, Exp> {
118    /// The underlying integer.
119    pub bits: Bits,
120
121    marker: PhantomData<(Base, Exp)>,
122}
123
124impl<Bits, Base, Exp> Fix<Bits, Base, Exp> {
125    /// Creates a number.
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// use fix::aliases::si::{Kilo, Milli};
131    /// Milli::new(25); // 0.025
132    /// Kilo::new(25); // 25 000
133    /// ```
134    pub fn new(bits: Bits) -> Self {
135        Fix { bits, marker: PhantomData }
136    }
137
138    /// Converts to another _Exp_.
139    ///
140    /// # Examples
141    ///
142    /// ```
143    /// use fix::aliases::si::{Kilo, Milli};
144    /// let kilo = Kilo::new(5);
145    /// let milli = Milli::new(5_000_000);
146    /// assert_eq!(kilo, milli.convert());
147    /// assert_eq!(milli, kilo.convert());
148    /// ```
149    pub fn convert<ToExp>(self) -> Fix<Bits, Base, ToExp>
150    where
151        Bits: FromUnsigned + Pow + Mul<Output = Bits> + Div<Output = Bits>,
152        Base: Unsigned,
153        Exp: Sub<ToExp>,
154        Diff<Exp, ToExp>: Abs + IsLess<Z0>,
155        AbsVal<Diff<Exp, ToExp>>: Integer
156    {
157        let base = Bits::from_unsigned::<Base>();
158        let diff = AbsVal::<Diff<Exp, ToExp>>::to_i32();
159        let inverse = Le::<Diff<Exp, ToExp>, Z0>::to_bool();
160
161        // FIXME: Would like to do this with typenum::Pow, but that
162        // seems to result in overflow evaluating requirements.
163        let ratio = base.pow(diff as u32);
164
165        if inverse {
166            Fix::new(self.bits / ratio)
167        } else {
168            Fix::new(self.bits * ratio)
169        }
170    }
171}
172
173/// Conversion from type-level [`Unsigned`] integers.
174///
175/// Enables being generic over types which can be created from type-level integers. It should
176/// probably be in `typenum` itself...
177///
178/// [`Unsigned`]: ../typenum/marker_traits/trait.Unsigned.html
179pub trait FromUnsigned {
180    /// Creates a value from a type.
181    fn from_unsigned<U>() -> Self where U: Unsigned;
182}
183
184impl FromUnsigned for u8 { fn from_unsigned<U: Unsigned>() -> Self { U::to_u8() } }
185impl FromUnsigned for u16 { fn from_unsigned<U: Unsigned>() -> Self { U::to_u16() } }
186impl FromUnsigned for u32 { fn from_unsigned<U: Unsigned>() -> Self { U::to_u32() } }
187impl FromUnsigned for u64 { fn from_unsigned<U: Unsigned>() -> Self { U::to_u64() } }
188impl FromUnsigned for usize { fn from_unsigned<U: Unsigned>() -> Self { U::to_usize() } }
189
190impl FromUnsigned for i8 { fn from_unsigned<U: Unsigned>() -> Self { U::to_i8() } }
191impl FromUnsigned for i16 { fn from_unsigned<U: Unsigned>() -> Self { U::to_i16() } }
192impl FromUnsigned for i32 { fn from_unsigned<U: Unsigned>() -> Self { U::to_i32() } }
193impl FromUnsigned for i64 { fn from_unsigned<U: Unsigned>() -> Self { U::to_i64() } }
194impl FromUnsigned for isize { fn from_unsigned<U: Unsigned>() -> Self { U::to_isize() } }
195
196/// Exponentiation.
197///
198/// Enables being generic over integers which can be exponentiated. Why must we do this, standard
199/// library?
200pub trait Pow {
201    /// Raises `self` to the power of `exp`.
202    fn pow(self, exp: u32) -> Self;
203}
204
205impl Pow for u8 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
206impl Pow for u16 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
207impl Pow for u32 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
208impl Pow for u64 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
209impl Pow for usize { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
210
211impl Pow for i8 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
212impl Pow for i16 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
213impl Pow for i32 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
214impl Pow for i64 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
215impl Pow for isize { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
216
217#[cfg(feature = "i128")]
218mod __i128 {
219    use super::*;
220    impl FromUnsigned for u128 { fn from_unsigned<U: Unsigned>() -> Self { U::to_u128() } }
221    impl FromUnsigned for i128 { fn from_unsigned<U: Unsigned>() -> Self { U::to_i128() } }
222    impl Pow for u128 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
223    impl Pow for i128 { #[inline] fn pow(self, exp: u32) -> Self { self.pow(exp) } }
224}
225
226// The usual traits.
227
228impl<Bits, Base, Exp> Copy for Fix<Bits, Base, Exp> where Bits: Copy { }
229impl<Bits, Base, Exp> Clone for Fix<Bits, Base, Exp>
230where Bits: Clone {
231    fn clone(&self) -> Self {
232        Self::new(self.bits.clone())
233    }
234}
235
236impl<Bits, Base, Exp> Default for Fix<Bits, Base, Exp>
237where Bits: Default {
238    fn default() -> Self {
239        Self::new(Bits::default())
240    }
241}
242
243impl<Bits, Base, Exp> Hash for Fix<Bits, Base, Exp>
244where Bits: Hash {
245    fn hash<H>(&self, state: &mut H) where H: Hasher {
246        self.bits.hash(state);
247    }
248}
249
250impl<Bits, Base, Exp> Debug for Fix<Bits, Base, Exp>
251where Bits: Debug, Base: Unsigned, Exp: Integer {
252    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
253        write!(f, "{:?}x{}^{}", self.bits, Base::to_u64(), Exp::to_i64())
254    }
255}
256
257// Comparison.
258
259impl<Bits, Base, Exp> Eq for Fix<Bits, Base, Exp> where Bits: Eq { }
260impl<Bits, Base, Exp> PartialEq for Fix<Bits, Base, Exp>
261where Bits: PartialEq {
262    fn eq(&self, rhs: &Self) -> bool {
263        self.bits == rhs.bits
264    }
265}
266
267impl<Bits, Base, Exp> PartialOrd for Fix<Bits, Base, Exp>
268where Bits: PartialOrd {
269    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
270        self.bits.partial_cmp(&rhs.bits)
271    }
272}
273
274impl<Bits, Base, Exp> Ord for Fix<Bits, Base, Exp>
275where Bits: Ord {
276    fn cmp(&self, rhs: &Self) -> Ordering {
277        self.bits.cmp(&rhs.bits)
278    }
279}
280
281// Arithmetic.
282
283impl<Bits, Base, Exp> Neg for Fix<Bits, Base, Exp>
284where Bits: Neg<Output = Bits> {
285    type Output = Self;
286    fn neg(self) -> Self {
287        Self::new(-self.bits)
288    }
289}
290
291impl<Bits, Base, Exp> Add for Fix<Bits, Base, Exp>
292where Bits: Add<Output = Bits> {
293    type Output = Self;
294    fn add(self, rhs: Self) -> Self {
295        Self::new(self.bits + rhs.bits)
296    }
297}
298
299impl<Bits, Base, Exp> Sub for Fix<Bits, Base, Exp>
300where Bits: Sub<Output = Bits> {
301    type Output = Self;
302    fn sub(self, rhs: Self) -> Self {
303        Self::new(self.bits - rhs.bits)
304    }
305}
306
307impl<Bits, Base, LExp, RExp> Mul<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
308where Bits: Mul<Output = Bits>, LExp: Add<RExp> {
309    type Output = Fix<Bits, Base, Sum<LExp, RExp>>;
310    fn mul(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
311        Self::Output::new(self.bits * rhs.bits)
312    }
313}
314
315impl<Bits, Base, LExp, RExp> Div<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
316where Bits: Div<Output = Bits>, LExp: Sub<RExp> {
317    type Output = Fix<Bits, Base, Diff<LExp, RExp>>;
318    fn div(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
319        Self::Output::new(self.bits / rhs.bits)
320    }
321}
322
323impl<Bits, Base, Exp> Rem for Fix<Bits, Base, Exp>
324where Bits: Rem<Output = Bits> {
325    type Output = Self;
326    fn rem(self, rhs: Self) -> Self {
327        Self::new(self.bits % rhs.bits)
328    }
329}
330
331impl<Bits, Base, Exp> Mul<Bits> for Fix<Bits, Base, Exp>
332where Bits: Mul<Output = Bits> {
333    type Output = Self;
334    fn mul(self, rhs: Bits) -> Self {
335        Self::new(self.bits * rhs)
336    }
337}
338
339impl<Bits, Base, Exp> Div<Bits> for Fix<Bits, Base, Exp>
340where Bits: Div<Output = Bits> {
341    type Output = Self;
342    fn div(self, rhs: Bits) -> Self {
343        Self::new(self.bits / rhs)
344    }
345}
346
347impl<Bits, Base, Exp> Rem<Bits> for Fix<Bits, Base, Exp>
348where Bits: Rem<Output = Bits> {
349    type Output = Self;
350    fn rem(self, rhs: Bits) -> Self {
351        Self::new(self.bits % rhs)
352    }
353}
354
355// Assignment.
356
357impl<Bits, Base, Exp> AddAssign for Fix<Bits, Base, Exp>
358where Bits: AddAssign {
359    fn add_assign(&mut self, rhs: Self) {
360        self.bits += rhs.bits;
361    }
362}
363
364impl<Bits, Base, Exp> SubAssign for Fix<Bits, Base, Exp>
365where Bits: SubAssign {
366    fn sub_assign(&mut self, rhs: Self) {
367        self.bits -= rhs.bits;
368    }
369}
370
371impl<Bits, Base, Exp> MulAssign<Bits> for Fix<Bits, Base, Exp>
372where Bits: MulAssign {
373    fn mul_assign(&mut self, rhs: Bits) {
374        self.bits *= rhs;
375    }
376}
377
378impl<Bits, Base, Exp> DivAssign<Bits> for Fix<Bits, Base, Exp>
379where Bits: DivAssign {
380    fn div_assign(&mut self, rhs: Bits) {
381        self.bits /= rhs;
382    }
383}
384
385impl<Bits, Base, LExp, RExp> RemAssign<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
386where Bits: RemAssign {
387    fn rem_assign(&mut self, rhs: Fix<Bits, Base, RExp>) {
388        self.bits %= rhs.bits;
389    }
390}
391
392impl<Bits, Base, Exp> RemAssign<Bits> for Fix<Bits, Base, Exp>
393where Bits: RemAssign {
394    fn rem_assign(&mut self, rhs: Bits) {
395        self.bits %= rhs;
396    }
397}
398
399#[cfg(test)]
400mod tests {
401    use aliases::si::{Kilo, Milli, Unit};
402
403    #[test]
404    fn convert_milli_to_kilo() {
405        assert_eq!(Kilo::new(15), Milli::new(15_000_000).convert());
406    }
407
408    #[test]
409    fn convert_kilo_to_milli() {
410        assert_eq!(Milli::new(15_000_000), Kilo::new(15).convert());
411    }
412
413    #[test]
414    fn cmp() {
415        assert!(Kilo::new(1) < Kilo::new(2));
416    }
417
418    #[test]
419    fn neg() {
420        assert_eq!(Kilo::new(-1), -Kilo::new(1i32));
421    }
422
423    #[test]
424    fn add() {
425        assert_eq!(Kilo::new(3), Kilo::new(1) + Kilo::new(2));
426    }
427
428    #[test]
429    fn sub() {
430        assert_eq!(Kilo::new(1), Kilo::new(3) - Kilo::new(2));
431    }
432
433    #[test]
434    fn mul() {
435        assert_eq!(Unit::new(6), Kilo::new(2) * Milli::new(3));
436    }
437
438    #[test]
439    fn div() {
440        assert_eq!(Unit::new(3), Kilo::new(6) / Kilo::new(2));
441    }
442
443    #[test]
444    fn rem() {
445        assert_eq!(Kilo::new(1), Kilo::new(6) % Kilo::new(5));
446    }
447
448    #[test]
449    fn mul_bits() {
450        assert_eq!(Kilo::new(6), Kilo::new(2) * 3);
451    }
452
453    #[test]
454    fn div_bits() {
455        assert_eq!(Kilo::new(3), Kilo::new(6) / 2);
456    }
457
458    #[test]
459    fn rem_bits() {
460        assert_eq!(Kilo::new(1), Kilo::new(6) % 5);
461    }
462
463    #[test]
464    fn add_assign() {
465        let mut a = Kilo::new(1);
466        a += Kilo::new(2);
467        assert_eq!(Kilo::new(3), a);
468    }
469
470    #[test]
471    fn sub_assign() {
472        let mut a = Kilo::new(3);
473        a -= Kilo::new(2);
474        assert_eq!(Kilo::new(1), a);
475    }
476
477    #[test]
478    fn mul_assign_bits() {
479        let mut a = Kilo::new(2);
480        a *= 3;
481        assert_eq!(Kilo::new(6), a);
482    }
483
484    #[test]
485    fn div_assign_bits() {
486        let mut a = Kilo::new(6);
487        a /= 2;
488        assert_eq!(Kilo::new(3), a);
489    }
490
491    #[test]
492    fn rem_assign() {
493        let mut a = Kilo::new(6);
494        a %= Milli::new(5);
495        assert_eq!(Kilo::new(1), a);
496    }
497
498    #[test]
499    fn rem_assign_bits() {
500        let mut a = Kilo::new(6);
501        a %= 5;
502        assert_eq!(Kilo::new(1), a);
503    }
504}