1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use crate::int::Sealed as _;
use crate::{Denominator, Integer, NotOne, Numerator, Recip, Q};
use core::ops::{Div, Rem};
use typenum::{Mod, Quot};

pub trait PrivateF64Helper {
    const F64: f64;
}

impl<N> PrivateF64Helper for Q<N>
where
    N: Numerator,
{
    const F64: f64 = N::F64;
}

impl<N, D> PrivateF64Helper for Q<N, D>
where
    N: Numerator<D> + Div<D> + Rem<D>,
    D: Denominator + NotOne + Numerator,
    Quot<N, D>: Integer,
    Mod<N, D>: Numerator<D>,
    Q<Mod<N, D>, D>: Recip,
    <Q<Mod<N, D>, D> as Recip>::Output: PrivateF64Helper,
{
    const F64: f64 =
        Quot::<N, D>::F64 + 1_f64 / <<Q<Mod<N, D>, D> as Recip>::Output as PrivateF64Helper>::F64;
}

pub trait Sealed: PrivateF64Helper {
    const F64: f64 = <Self as PrivateF64Helper>::F64;
}

impl<N, D> Sealed for Q<N, D>
where
    Self: PrivateF64Helper,
    N: Numerator<D>,
    D: Denominator,
{
}

/// Type-level rational numbers.
pub trait Rational: 'static + Default + Copy + Sealed {
    /// Approximate 64-bit floating point number of this rational number.
    ///
    /// # Examples
    ///
    /// ```
    /// use typerat::*;
    ///
    /// assert_eq!(Q::<Z0>::F64, 0_f64);
    /// assert_eq!(Q::<P1>::F64, 1_f64);
    /// assert_eq!(Q::<N1>::F64, -1_f64);
    /// assert_eq!(Q::<N1, P2>::F64, -0.5_f64);
    /// assert_eq!(Q::<P1, P3>::F64, 1_f64 / 3_f64);
    /// assert_eq!(Q::<N5, P3>::F64, -1_f64 - 1_f64 / 1.5_f64);
    /// ```
    const F64: f64 = <Self as PrivateF64Helper>::F64;
}

impl<N, D> Rational for Q<N, D>
where
    Self: Sealed,
    N: Numerator<D>,
    D: Denominator,
{
}