CarpetX: a Cactus driver for the Einstein Toolkit based on AMReX
#include "rational.hxx"

#include <numeric>

namespace Arith {
using namespace std;

template <typename I> constexpr bool isgood(const rational<I> &x) {
  return x.den >= 0 && gcd(x.num, x.den) == 1;
}

// This function is compiled, but not executed. The tests are "run" at
// compile time. If this function compiles, the tests pass.
void TestRational() {
  using rat64 = rational<int64_t>;
  static_assert(rat64().num == 0);
  static_assert(rat64(1).num == 1);
  static_assert(rat64(1, 2).num == 1);
  static_assert(rat64(2, 4).num == 1);
  static_assert(rat64().den == 1);
  static_assert(rat64(1).den == 1);
  static_assert(rat64(1, 2).den == 2);
  static_assert(rat64(2, 4).den == 2);

  constexpr auto n = rat64();
  constexpr auto e = rat64(1);
  constexpr auto x = rat64(1, 2);
  constexpr auto y = rat64(2, 3);
  constexpr auto z = rat64(3, 4);
  constexpr auto a = 4;

  +x;
  -x;

  x + y;
  x - y;
  x *y;
  x / y;

  a + y;
  a - y;
  a *y;
  a / y;

  x + a;
  x - a;
  x *a;
  x / a;

  auto r = x;
  r = x;
  r += y;
  r = x;
  r -= y;
  r = x;
  r *= y;
  r = x;
  r /= y;

  r = x;
  r += a;
  r = x;
  r -= a;
  r = x;
  r *= a;
  r = x;
  r /= a;

  x == y;
  x != y;
  x < y;
  x > y;
  x <= y;
  x >= y;

  a == y;
  a != y;
  a < y;
  a > y;
  a <= y;
  a >= y;

  x == a;
  x != a;
  x < a;
  x > a;
  x <= a;
  x >= a;

  static_assert(isgood(abs(x)));

  static_assert(isgood(max(x, y)));
  static_assert(isgood(min(x, y)));

  static_assert(isgood(pow(x, a)));

  static_assert(+x == n + x);
  static_assert(x + n == x);
  static_assert(n + x == x);
  static_assert(x + (y + z) == (x + y) + z);
  static_assert(x + y == y + x);

  static_assert(-x == n - x);
  static_assert(-(-x) == x);
  static_assert(x + (-y) == x - y);
  static_assert(x - x == n);

  static_assert(x * e == x);
  static_assert(e * x == x);
  static_assert(x * (y * z) == (x * y) * z);
  static_assert(x * y == y * x);
  static_assert(n * x == n);

  static_assert(1 / (1 / x) == x);
  static_assert(x / x == e);

  static_assert(x * (y + z) == x * y + x * z);
}

} // namespace Arith