1 #if !defined(sol_math_ratio_hpp_included)
2 #define sol_math_ratio_hpp_included
3 /// \addtogroup sol_math
8 * \file sol/math/ratio.hpp
9 * \brief Compute rational values at compile time
11 * \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm#ratio
13 * \todo ratio comparison
18 #include <sol/cstdint.hpp>
19 #include <sol/math/abs.hpp>
20 #include <sol/math/gcd.hpp>
21 #include <sol/math/sign.hpp>
22 #include <sol/static_assert.hpp>
23 #include <sol/utility/integral_constant.hpp>
26 namespace sol
{ namespace math
{
32 #if !defined(INTMAX_MAX)
33 #define INTMAX_MAX INT_MAX
37 template <intmax_t A
, intmax_t B
, bool IsPositiveB
>
39 : integral_constant
<bool, (A
<= INTMAX_MAX
- B
)>
43 template <intmax_t A
, intmax_t B
>
44 struct add_overflow
<A
, B
, false>
45 : integral_constant
<bool, (A
>= -INTMAX_MAX
- B
)>
49 template <intmax_t A
, intmax_t B
>
52 static_assert((add_overflow
<A
, B
, B
>= 0>::value
== true), "overflow");
53 static intmax_t const value
= A
+ B
;
57 template <intmax_t A
, intmax_t B
>
60 static uintmax_t const c
= 1UL << (4*sizeof(intmax_t));
62 static uintmax_t const a0
= abs
<A
>::value
%c
;
63 static uintmax_t const a1
= abs
<A
>::value
/c
;
64 static uintmax_t const b0
= abs
<B
>::value
%c
;
65 static uintmax_t const b1
= abs
<B
>::value
/c
;
67 static_assert(a1
== 0 || b1
== 0, "overflow");
68 static_assert((a0
*b1
+ b0
*a1
) < (c
>> 1), "overflow");
69 static_assert(b0
*a0
<= INTMAX_MAX
, "overflow");
70 static_assert((a0
*b1
+ b0
*a1
)*c
<= INTMAX_MAX
- b0
*a0
, "overflow");
72 static intmax_t const value
= A
*B
;
79 /// Rational value representation (calculated during compile-time)
80 template <intmax_t N
, intmax_t D
=1>
83 static_assert(D
!= 0, "division by 0");
86 static intmax_t const num
= N
*sign
<D
>::value
/gcd
<N
, D
>::value
;
89 static intmax_t const den
= abs
<D
>::value
/gcd
<N
, D
>::value
;
93 /// rational arithmetic: addition
94 template <typename R1
, typename R2
>
99 enum { g
= gcd
<R1::den
, R2::den
>::value
};
107 bits::multiply_
<R1::num
, R2::den
/g
>::value
108 , bits::multiply_
<R2::num
, R1::den
/g
>::value
110 , bits::multiply_
<R1::den
, R2::den
/g
>::value
115 /// rational arithmetic: subtraction
116 template <typename R1
, typename R2
>
117 struct ratio_subtract
120 typedef typename ratio_add
<
122 , ratio
<-R2::num
, R2::den
>
127 /// rational arithmetic: multiplication
128 template <typename R1
, typename R2
>
129 struct ratio_multiply
134 g1
= gcd
<R1::num
, R2::den
>::value
135 , g2
= gcd
<R2::num
, R1::den
>::value
142 bits::multiply_
<R1::num
/g1
, R2::num
/g2
>::value
143 , bits::multiply_
<R1::den
/g2
, R2::den
/g1
>::value
148 /// rational arithmetic: division
149 template <typename R1
, typename R2
>
152 static_assert(R2::num
!= 0, "division by 0");
155 typedef typename ratio_multiply
<
157 , ratio
<R2::den
, R2::num
>
162 /// Comparison: R1 == R2
163 template <typename R1
, typename R2
>
165 : integral_constant
<bool, R1::num
== R2::num
&& R1::den
== R2::den
>
169 /// Comparison: R1 != R2
170 template <typename R1
, typename R2
>
171 struct ratio_not_equal
172 : integral_constant
<bool, !ratio_equal
<R1
, R2
>::value
>
176 /// Comparison: R1 < R2
177 template <typename R1
, typename R2
>
179 : integral_constant
<bool
180 , bits::multiply_
<R1::num
, R2::den
>::value
181 < bits::multiply_
<R2::num
, R1::den
>::value
186 /// Comparison: R1 <= R2
187 template <typename R1
, typename R2
>
188 struct ratio_less_equal
189 : integral_constant
<bool, !ratio_less
<R2
, R1
>::value
>
193 /// Comparison: R1 > R2
194 template <typename R1
, typename R2
>
196 : integral_constant
<bool, ratio_less
<R2
, R1
>::value
>
200 /// Comparison: R1 >= R2
201 template <typename R1
, typename R2
>
202 struct ratio_greater_equal
203 : integral_constant
<bool, !ratio_less
<R1
, R2
>::value
>
207 /// Convenience SI units
209 typedef ratio
<1, 1000000000000000000> atto
;
210 typedef ratio
<1, 1000000000000000> femto
;
211 typedef ratio
<1, 1000000000000> pico
;
212 typedef ratio
<1, 1000000000> nano
;
213 typedef ratio
<1, 1000000> micro
;
214 typedef ratio
<1, 1000> milli
;
215 typedef ratio
<1, 100> centi
;
216 typedef ratio
<1, 10> deci
;
217 typedef ratio
< 10, 1> deca
;
218 typedef ratio
< 100, 1> hecto
;
219 typedef ratio
< 1000, 1> kilo
;
220 typedef ratio
< 1000000, 1> mega
;
221 typedef ratio
< 1000000000, 1> giga
;
222 typedef ratio
< 1000000000000, 1> tera
;
223 typedef ratio
< 1000000000000000, 1> peta
;
224 typedef ratio
<1000000000000000000, 1> exa
;
228 }} // namespace sol::math
232 #endif // sol_math_ratio_hpp_included