1 #ifndef __DUNE_ACFEM_COMMON_FRACTIONCONSTANT_HH__
2 #define __DUNE_ACFEM_COMMON_FRACTIONCONSTANT_HH__
8 #include <dune/acfem/common/types.hh>
13 namespace TypedValue {
25 template<
class Int, Int N, Int D>
28 using IntegerType = Int;
29 static constexpr IntegerType numerator = N;
30 static constexpr IntegerType denominator = D;
32 static_assert(D > 0 && (std::gcd(N, D) == 1 || std::gcd(N, D) == -1),
33 "GCD should be 1 here ... oops");
38 template<
class Int2, Int2 N2, Int2 D2>
41 static_assert((N == (Int)N2 / std::gcd((Int)N2, (Int)D2))
43 (D == (Int)D2 / std::gcd((Int)N2, (Int)D2)),
44 "Assignment from integral constants only possible if their quotient matches the value of the fraction");
47 template<
class Int2, Int2 N2>
63 template<
class T, std::enable_if_t<std::numeric_limits<std::decay_t<T> >::is_specialized,
int> = 0>
64 constexpr
operator T()
const
66 return static_cast<T
>(N) /
static_cast<T
>(D);
72 template<
class T,
bool RequireDecay = false,
class SFINAE =
void>
82 template<
class I, I N, I D,
bool RequireDecay>
88 constexpr T sign(T val) {
89 return (T(0) < val) - (val < T(0));
93 constexpr T abs(T val) {
94 return sign(val) * val;
100 template<
class I, I N, I D = 1>
103 sign(D) * N / std::gcd(N, D),
104 abs(D) / std::gcd(N, D)>;
107 template<std::ptrdiff_t N, std::ptrdiff_t D = 1>
108 using IntFraction = Fraction<std::ptrdiff_t, N, D>;
123 template<std::ptrdiff_t N, std::ptrdiff_t D = 1>
124 constexpr
auto intFraction(IntConstant<N> = IntConstant<N>{}, IntConstant<D> = IntConstant<D>{})
126 return IntFraction<N, D>{};
129 template<std::
size_t N, std::
size_t D = 1>
130 constexpr
auto intFraction(IndexConstant<N>, IndexConstant<D> = IndexConstant<D>{})
132 return IntFraction<(std::ptrdiff_t)N, (std::ptrdiff_t)D>{};
136 constexpr std::ptrdiff_t numerator(T&& t = T{})
138 static_assert(IsFractionConstant<T>::value,
"T must fulfil IsFractionConstant<T>");
139 return std::decay_t<T>::numerator;
143 constexpr std::ptrdiff_t denominator(T&& t = T{})
145 static_assert(IsFractionConstant<T>::value,
"T must fulfil IsFractionConstant<T>");
146 return std::decay_t<T>::denominator;
150 template<std::ptrdiff_t S>
151 using Sign = IntFraction<(S > 0 ? 1 : (S < 0 ? -1 : 0))>;
154 template<std::ptrdiff_t S>
155 constexpr
auto sign(IntConstant<S> = IntConstant<S>{})
162 using SignOf = Sign<T{}>;
166 constexpr
auto signOf(T&&)
172 template<
class T,
class SFINAE =
void>
177 struct IsSign<T, std::enable_if_t<!IsFractionConstant<T>::value> >
185 struct IsSign<T, std::enable_if_t<IsFractionConstant<T>::value> >
186 :
BoolConstant<(numerator<T>()*numerator<T>() <= 1 && denominator<T>() == 1)>
190 template<class T1, class T2>
191 using FieldPromotionType = std::decay_t<decltype(std::declval<T1>() * std::declval<T2>())>;
193 template<class I, I N, I D>
194 constexpr auto operator-(FractionConstant<I, N, D>)
196 return Fraction<I, -N, D>{};
199 template<class I, I N, I D>
200 constexpr auto reciprocal(FractionConstant<I, N, D>)
202 static_assert(N != 0, "Reciprocal of zero attempted.");
203 return Fraction<I, D, N>{};
206 template<class I1, I1 N1, I1 D1,
207 class I2, I2 N2, I2 D2>
208 constexpr auto operator*(FractionConstant<I1, N1, D1>, FractionConstant<I2, N2, D2>)
211 using T1 = Fraction<I1, N1, D1>;
212 using T2 = Fraction<I2, N2, D2>;
215 using C1 = Fraction<FieldPromotionType<I1, I2>, T1::numerator, T2::denominator>;
216 using C2 = Fraction<FieldPromotionType<I1, I2>, T2::numerator, T1::denominator>;
219 return Fraction<FieldPromotionType<I1, I2>,
220 C1::numerator * C2::numerator,
221 C1::denominator * C2::denominator>{};
224 template<class I1, I1 N1, I1 D1,
225 class I2, I2 N2, I2 D2>
226 constexpr auto operator+(FractionConstant<I1, N1, D1>, FractionConstant<I2, N2, D2>)
229 using Int = FieldPromotionType<I1, I2>;
230 using T1 = Fraction<Int, N1, D1>;
231 using T2 = Fraction<Int, N2, D2>;
236 constexpr Int denomGcd = std::gcd(T1::denominator, T2::denominator);
237 constexpr Int denom1 = T1::denominator/denomGcd;
238 constexpr Int denom2 = T2::denominator/denomGcd;
241 T1::numerator*denom2 + T2::numerator*denom1,
242 denom1*denom2*denomGcd>{};
245 template<class I1, I1 N1, I1 D1,
246 class I2, I2 N2, I2 D2>
247 constexpr auto operator-(FractionConstant<I1, N1, D1>, FractionConstant<I2, N2, D2>)
250 using Int = FieldPromotionType<I1, I2>;
251 using T1 = Fraction<Int, N1, D1>;
252 using T2 = Fraction<Int, N2, D2>;
257 constexpr Int denomGcd = std::gcd(T1::denominator, T2::denominator);
258 constexpr Int denom1 = T1::denominator/denomGcd;
259 constexpr Int denom2 = T2::denominator/denomGcd;
262 T1::numerator*denom2 - T2::numerator*denom1,
263 denom1*denom2*denomGcd>{};
266 template<class I1, I1 N1, I1 D1,
267 class I2, I2 N2, I2 D2>
268 constexpr auto operator/(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
270 static_assert(N2 != 0, "Division by Zero.");
272 return f1 * reciprocal(f2);
275 template<class I1, I1 N1, class I2, I2 N2>
276 constexpr auto operator%(FractionConstant<I1, N1, 1>, FractionConstant<I2, N2, 1>)
278 return Fraction<FieldPromotionType<I1, I2>, (N1 % N2), 1>{};
281 template<class I1, I1 N1, class I2, I2 N2>
282 constexpr auto div(FractionConstant<I1, N1, 1>, FractionConstant<I2, N2, 1>)
284 return Fraction<FieldPromotionType<I1, I2>, N1 / N2, 1>{};
288 template<class I1, I1 N1, I1 D1, class I2>
289 constexpr auto pow(FractionConstant<I1, N1, D1>, FractionConstant<I2, 0, 1>)
291 return FractionConstant<I1, 1, 1>{};
295 template<class I1, I1 N1, I1 D1, class I2>
296 constexpr auto pow(FractionConstant<I1, N1, D1>, FractionConstant<I2, 1, 1>)
298 return FractionConstant<I1, N1, D1>{};
302 template<class I1, I1 N1, I1 D1, class I2, I2 N2, std::enable_if_t<(N2 > 1), int> = 0>
303 constexpr auto
pow(FractionConstant<I1, N1, D1>, FractionConstant<I2, N2, 1>)
308 template<
class I, I N, I D>
315 template<
class I1, I1 N1, I1 D1,
class I2, I2 N2, std::enable_if_t<(N2 < 0 && N1 != 0),
int> = 0>
316 constexpr auto pow(FractionConstant<I1, N1, D1>, FractionConstant<I2, N2, 1>)
318 return pow(Fraction<I1, D1, N1>{}, FractionConstant<I2, N2, 1>{});
321 template<
class I, I N, I D>
322 constexpr
auto floor(FractionConstant<I, N, D>)
324 if constexpr (D == 1) {
325 return FractionConstant<I, N, 1>{};
326 }
else if constexpr (N < 0) {
329 return FractionConstant<I, N/D-1, 1>{};
332 return FractionConstant<I, N/D, 1>{};
336 template<
class I, I N, I D>
337 constexpr
auto ceil(FractionConstant<I, N, D>)
339 if constexpr (D == 1) {
340 return FractionConstant<I, N, 1>{};
344 return FractionConstant<I, (N+1)/D, 1>{};
349 template<
class I, I N, I D>
350 constexpr
auto round(FractionConstant<I, N, D>)
353 return FractionConstant<I, (N < 0 ? (N-D/2)/D : (N-D/2)/D) , 1>{};
356 template<
class I, I N, I D>
357 constexpr
auto abs(FractionConstant<I, N, D>)
359 if constexpr (N < 0) {
360 return FractionConstant<I, -N, D>{};
362 return FractionConstant<I, N, D>{};
366 template<
class I1, I1 N1, I1 D1,
367 class I2, I2 N2, I2 D2>
368 constexpr
bool operator==(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
371 using Int = FieldPromotionType<I1, I2>;
374 using T1 = Fraction<Int, N1, D1>;
375 using T2 = Fraction<Int, N2, D2>;
378 constexpr Int denomGcd = std::gcd(T1::denominator, T2::denominator);
379 constexpr Int denom1 = T1::denominator/denomGcd;
380 constexpr Int denom2 = T2::denominator/denomGcd;
382 return T1::numerator*denom2 == T2::numerator*denom1;
385 template<
class I1, I1 N1, I1 D1,
386 class I2, I2 N2, I2 D2>
387 constexpr
bool operator!=(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
392 template<
class I1, I1 N1, I1 D1,
393 class I2, I2 N2, I2 D2>
394 constexpr
bool operator<(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
397 using Int = FieldPromotionType<I1, I2>;
400 using T1 = Fraction<Int, N1, D1>;
401 using T2 = Fraction<Int, N2, D2>;
404 constexpr Int denomGcd = std::gcd(T1::denominator, T2::denominator);
405 constexpr Int denom1 = T1::denominator/denomGcd;
406 constexpr Int denom2 = T2::denominator/denomGcd;
408 return T1::numerator*denom2 < T2::numerator*denom1;
411 template<
class I1, I1 N1, I1 D1,
412 class I2, I2 N2, I2 D2>
413 constexpr
bool operator<=(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
415 return f1 < f2 || f1 == f2;
418 template<
class I1, I1 N1, I1 D1,
419 class I2, I2 N2, I2 D2>
420 constexpr
bool operator>(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
425 template<
class I1, I1 N1, I1 D1,
426 class I2, I2 N2, I2 D2>
427 constexpr
bool operator>=(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
434 template<
class I1, I1 N1, I1 D1,
435 class I2, I2 N2, I2 D2,
436 std::enable_if_t<!std::is_same<FractionConstant<I1, N1, D1>,
437 FractionConstant<I2, N2, D2> >::value,
int> = 0>
438 constexpr
auto min(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
440 if constexpr (f1 <= f2) {
449 template<
class I1, I1 N1, I1 D1,
450 class I2, I2 N2, I2 D2,
451 std::enable_if_t<!std::is_same<FractionConstant<I1, N1, D1>,
452 FractionConstant<I2, N2, D2> >::value,
int> = 0>
453 constexpr
auto max(FractionConstant<I1, N1, D1> f1, FractionConstant<I2, N2, D2> f2)
455 if constexpr (f1 >= f2) {
462 template<
class I, I N, I D>
463 std::string toString(FractionConstant<I, N, D>)
466 using T = Fraction<I, N, D>;
467 if constexpr (T::denominator == 1) {
468 return std::to_string(T::numerator) +
"_c";
470 return "(" + std::to_string(T::numerator) +
"/" + std::to_string(T::denominator) +
")_c";
475 template<
class I, I N, I D>
476 std::ostream&
operator<<(std::ostream& out, FractionConstant<I, N, D> frac)
478 return out << toString(frac);
484 using IsFractionConstant = TypedValue::IsFractionConstant<T>;
std::ostream & operator<<(std::ostream &out, TypeString< T > &&t)
Output operator for TypePrint tag-structure.
Definition: ostream.hh:39
auto pow(T1 &&t1, T2 &&t2)
Power operations with scalar exponents are promoted to component-wise power operations by multiplying...
Definition: expressions.hh:525
integral_constant< T, V > Constant
Short-cut for any integral constant.
Definition: types.hh:40
Constant< bool, V > BoolConstant
Short-cut for integral constant of type bool.
Definition: types.hh:48
BoolConstant< false > FalseType
Alias for std::false_type.
Definition: types.hh:110
BoolConstant< true > TrueType
Alias for std::true_type.
Definition: types.hh:107
A class implementing compile-time constant fractions of integers.
Definition: fractionconstant.hh:27
Definition: fractionconstant.hh:75
Definition: fractionconstant.hh:173