#include <iostream>
#include <ratio>
#include <iostream>
#include <sstream>
#include <ctgmath>
namespace unit {
template <typename Unit, typename MagnitudeRepresentation = double>
class Quantity {
template <typename, typename>
friend class Quantity;
public:
using unit = Unit;
using magnitude_type = MagnitudeRepresentation;
using classtype = Quantity<unit, magnitude_type>;
constexpr explicit Quantity() : m_magnitude(0) {}
constexpr explicit Quantity(magnitude_type const& v) : m_magnitude(v) {}
constexpr Quantity(classtype const& v) = default;
template <typename R>
constexpr Quantity(Quantity<unit, R> const& v) : m_magnitude(v.m_magnitude) {}
classtype& operator=(classtype const& v) = default;
constexpr magnitude_type const& magnitude() const { return m_magnitude; }
private:
template <typename U, typename L, typename R>
friend constexpr Quantity<U, L>& operator+=(Quantity<U, L>&, Quantity<U, R> const&);
template <typename U, typename L, typename R>
friend constexpr Quantity<U, L>& operator-=(Quantity<U, L>&, Quantity<U, R> const&);
template <typename U, typename L, typename R>
friend constexpr Quantity<U, L>& operator*=(Quantity<U, L>&, Quantity<U, R> const&);
template <typename U, typename L, typename R>
friend constexpr Quantity<U, L>& operator/=(Quantity<U, L>&, Quantity<U, R> const&);
magnitude_type m_magnitude;
};
using TExponent = int;
using ExponentIndex = int;
using DimensionIndex = int;
template <TExponent... dimensionExponents>
struct Unit;
namespace helper {
template <typename Unit, ExponentIndex i>
constexpr TExponent exponent() {
return Unit::template exponent_value<i>();
}
namespace nthElement {
using Index = unsigned int;
template <Index n, TExponent Arg, TExponent... Args>
struct NthElement {
static constexpr int value() { return NthElement<n - 1, Args...>::value(); }
};
template <TExponent Arg, TExponent... Args>
struct NthElement<0, Arg, Args...> {
static constexpr int value() { return Arg; }
};
}
namespace baseunit {
template <DimensionIndex it, DimensionIndex index, TExponent... exponents>
struct BaseUnitGen {
using type = typename BaseUnitGen<it - 1, index, it == index ? 1 : 0, exponents...>::type;
};
template <DimensionIndex index, TExponent... exponents>
struct BaseUnitGen<-1, index, exponents...> {
using type = Unit<exponents...>;
};
}
}
template <int dimension, int lastDimension>
using BaseUnit = typename helper::baseunit::BaseUnitGen<lastDimension, dimension>::type;
template<TExponent ... dimensionExponents >
struct Unit{
using classtype = Unit<dimensionExponents...>;
static constexpr unsigned exponent_count() {return sizeof...(dimensionExponents);}
template<ExponentIndex i>
static constexpr TExponent exponent_value() { return helper::nthElement::NthElement<i,dimensionExponents...>::value(); }
};
namespace helper {
namespace op {
template <typename U1, typename U2, int index>
struct sum {
static constexpr int value() { return U1::template exponent_value<index>() + U2::template exponent_value<index>(); }
};
template <typename U1, typename U2, int index>
struct difference {
static constexpr int value() { return U1::template exponent_value<index>() - U2::template exponent_value<index>(); }
};
template <typename U1, typename fract, int index>
struct multiply {
static_assert(helper::exponent<U1, index>() * fract::num % fract::den == 0,
"rasing a unit to a fractional-power is not allowed");
static constexpr int value() { return helper::exponent<U1, index>() * fract::num / fract::den; }
};
template <ExponentIndex it, typename U1, typename U2, template <class, class, int> class Op, TExponent... exponents>
struct UnitOperator {
using type = typename UnitOperator<it - 1, U1, U2, Op, Op<U1, U2, it>::value(), exponents...>::type;
};
template <typename U1, typename U2, template <class, class, int> class Op, TExponent... exponents>
struct UnitOperator<-1, U1, U2, Op, exponents...> {
using type = Unit<exponents...>;
};
}
}
template <typename U1, typename U2>
using product_unit = typename helper::op::UnitOperator<U1::exponent_count() - 1, U1, U2, helper::op::sum>::type;
template <typename U1, typename U2>
using quotient_unit = typename helper::op::UnitOperator<U1::exponent_count() - 1, U1, U2, helper::op::difference>::type;
template <typename U1, typename fract>
using raised_unit = typename helper::op::UnitOperator<U1::exponent_count() - 1, U1, fract, helper::op::multiply>::type;
template <typename U>
using sqare_unit = product_unit<U, U>;
template <typename TDst, typename QSrc>
constexpr Quantity<typename QSrc::unit, TDst> static_unit_cast(QSrc const& l) {
return Quantity<typename QSrc::unit, TDst>{static_cast<TDst>(l.magnitude())};
}
template <typename U, typename LT, typename RT>
constexpr Quantity<U, LT>& operator+=(Quantity<U, LT>& l, Quantity<U, RT> const& r) {
return l.m_magnitude += r.m_magnitude, l;
}
template <typename U, typename LT, typename RT>
constexpr Quantity<U, LT>& operator-=(Quantity<U, LT>& l, Quantity<U, RT> const& r) {
return l.m_magnitude -= r.m_magnitude, l;
}
template <typename U, typename LT, typename RT>
constexpr Quantity<U, LT>& operator*=(Quantity<U, LT>& l, Quantity<U, RT> const& r) {
return l.m_magnitude *= r.m_magnitude, l;
}
template <typename U, typename LT, typename RT>
constexpr Quantity<U, LT>& operator/=(Quantity<U, LT>& l, Quantity<U, RT> const& r) {
return l.m_magnitude /= r.m_magnitude, l;
}
template <typename LU, typename LT, typename RU, typename RT>
constexpr auto operator*(Quantity<LU, LT> const& l, Quantity<RU, RT> const& r)
-> Quantity<product_unit<LU, RU>, decltype(l.magnitude() * r.magnitude())> {
return Quantity<product_unit<LU, RU>, decltype(l.magnitude() * r.magnitude())>{l.magnitude() * r.magnitude()};
}
template <typename LU, typename LT, typename RU, typename RT>
constexpr auto operator/(Quantity<LU, LT> const& l, Quantity<RU, RT> const& r)
-> Quantity<quotient_unit<LU, RU>, decltype(l.magnitude() / r.magnitude())> {
return Quantity<quotient_unit<LU, RU>, decltype(l.magnitude() / r.magnitude())>{l.magnitude() / r.magnitude()};
}
template <typename U, typename LT, typename RT>
constexpr auto operator+(Quantity<U, LT> const& l, Quantity<U, RT> const& r)
-> Quantity<U, decltype(l.magnitude() + r.magnitude())> {
return Quantity<U, decltype(l.magnitude() + r.magnitude())>{l.magnitude() + r.magnitude()};
}
template <typename U, typename LT, typename RT>
constexpr auto operator-(Quantity<U, LT> const& l, Quantity<U, RT> const& r)
-> Quantity<U, decltype(l.magnitude() - r.magnitude())> {
return Quantity<U, decltype(l.magnitude() - r.magnitude())>{l.magnitude() - r.magnitude()};
}
template <typename U, typename LT, typename RT>
constexpr bool operator<(Quantity<U, LT> const& l, Quantity<U, RT> const& r) {
return l.magnitude() < r.magnitude();
}
template <typename U, typename LT, typename RT>
constexpr bool operator<=(Quantity<U, LT> const& l, Quantity<U, RT> const& r) {
return l.magnitude() <= r.magnitude();
}
template <typename U, typename LT, typename RT>
constexpr bool operator>(Quantity<U, LT> const& l, Quantity<U, RT> const& r) {
return l.magnitude() > r.magnitude();
}
template <typename U, typename LT, typename RT>
constexpr bool operator>=(Quantity<U, LT> const& l, Quantity<U, RT> const& r) {
return l.magnitude() >= r.magnitude();
}
template <typename U, typename LT, typename RT>
constexpr bool operator==(Quantity<U, LT> const& l, Quantity<U, RT> const& r) {
return l.magnitude() == r.magnitude();
}
template <typename U, typename LT, typename RT>
constexpr bool operator!=(Quantity<U, LT> const& l, Quantity<U, RT> const& r) {
return l.magnitude() != r.magnitude();
}
template <typename LU, typename LT>
constexpr Quantity<LU, LT> operator-(Quantity<LU, LT> const& l) {
return Quantity<LU, LT>{-l.magnitude()};
}
template <typename U, typename T>
constexpr auto
abs(Quantity<U, T> const& q)
-> Quantity<U, decltype(abs(q.magnitude()))>
{
using std::abs;
return Quantity<U, decltype(abs(q.magnitude()))>{
abs(q.magnitude())};
}
template <typename U, typename T>
constexpr auto
sqrt(Quantity<U, T> const& q)
-> Quantity<raised_unit<U, std::ratio<1, 2>>, decltype(sqrt(q.magnitude()))>
{
using std::sqrt;
return Quantity<raised_unit<U, std::ratio<1, 2>>, decltype(sqrt(q.magnitude()))>{
sqrt(q.magnitude())};
}
namespace helper {
template <typename power, typename T>
constexpr auto
pow_impl(T const& v)
-> decltype(pow(v, static_cast<double>(power::num) / static_cast<double>(power::den)))
{
using std::pow;
return pow(v, static_cast<double>(power::num) / static_cast<double>(power::den));
}
}
template <typename power, typename U, typename T>
constexpr auto
pow(Quantity<U, T> const& q)
-> Quantity<raised_unit<U, power>, decltype(helper::pow_impl<power, T>(q.magnitude()))>
{
return Quantity<raised_unit<U, power>, decltype(helper::pow_impl<power, T>(q.magnitude()))>{
helper::pow_impl<power, T>(q.magnitude())};
}
template <typename U, typename T>
constexpr auto
cube(Quantity<U, T> const& q)
-> Quantity<product_unit<product_unit<U, U>, U>, decltype((q.magnitude() * q.magnitude()) * q.magnitude())>
{
return Quantity<product_unit<product_unit<U, U>, U>, decltype((q.magnitude() * q.magnitude()) * q.magnitude())>{
(q.magnitude() * q.magnitude()) * q.magnitude()};
}
template <typename U, typename T>
constexpr auto
square(Quantity<U, T> const& q)
-> Quantity<product_unit<U, U>, decltype(q.magnitude() * q.magnitude())>
{
return Quantity<product_unit<U, U>, decltype(q.magnitude() * q.magnitude())>{
q.magnitude() * q.magnitude()};
}
template <typename U>
constexpr const char* unitSymbol();
namespace helper {
namespace print {
template <typename U, DimensionIndex pos>
void print_unit_symbol_and_exponent(std::ostream& s) {
static constexpr TExponent e = helper::exponent<U, pos>();
if (e == 0)
return;
s << unitSymbol<typename baseunit::BaseUnitGen<U::exponent_count() - 1, pos>::type>();
if (e != 1) {
s << "^" << e;
}
}
template <typename U, DimensionIndex pos>
struct DimensionsPrinter {
static void print_unit(std::ostream& s) {
DimensionsPrinter<U, pos - 1>::print_unit(s);
print_unit_symbol_and_exponent<U, pos>(s);
}
};
template <typename U>
struct DimensionsPrinter<U, 0> {
static void print_unit(std::ostream& s) { print_unit_symbol_and_exponent<U, 0>(s); }
};
}
}
template <typename U>
void print_unit(std::ostream& s) {
helper::print::DimensionsPrinter<U, U::exponent_count() - 1>::print_unit(s);
}
template <typename Unit>
std::istream& read_unit(std::istream& s) {
std::ostringstream expectedBuff;
print_unit<Unit>(expectedBuff);
for (auto const& expected : expectedBuff.str()) {
char found;
s >> found;
if (!s || found != expected) {
s.setstate(std::ios::failbit);
return s;
}
}
return s;
}
template <typename Unit, typename TValue>
std::istream& operator>>(std::istream& s, Quantity<Unit, TValue>& v) {
TValue val;
s >> val;
if (!s)
return s;
if (!read_unit<Unit>(s))
return s;
v = Quantity<Unit, TValue>{val};
return s;
}
template <typename Unit, typename TValue>
std::ostream& operator<<(std::ostream& s, Quantity<Unit, TValue> const& v) {
s << v.magnitude();
print_unit<Unit>(s);
return s;
}
namespace helper {
template <typename ratioIn, typename ratioOut, typename T>
constexpr T rescale(T const& v) {
using r = std::ratio_divide<ratioIn, ratioOut>;
return v * T{r::num} / T{r::den};
}
template <typename ratioIn, typename T>
constexpr T rescaleTo1(T const& v) {
return rescale<ratioIn, std::ratio<1>, T>(v);
}
}
template<typename T> constexpr T femto(T const& v) { return helper::rescaleTo1<std::femto>(v); }
template<typename T> constexpr T pico(T const& v) { return helper::rescaleTo1<std::pico>(v); }
template<typename T> constexpr T nano(T const& v) { return helper::rescaleTo1<std::nano>(v); }
template<typename T> constexpr T micro(T const& v) { return helper::rescaleTo1<std::micro>(v); }
template<typename T> constexpr T milli(T const& v) { return helper::rescaleTo1<std::milli>(v); }
template<typename T> constexpr T centi(T const& v) { return helper::rescaleTo1<std::centi>(v); }
template<typename T> constexpr T deci(T const& v) { return helper::rescaleTo1<std::deci>(v); }
template<typename T> constexpr T deca(T const& v) { return helper::rescaleTo1<std::deca>(v); }
template<typename T> constexpr T hecto(T const& v) { return helper::rescaleTo1<std::hecto>(v); }
template<typename T> constexpr T kilo(T const& v) { return helper::rescaleTo1<std::kilo>(v); }
template<typename T> constexpr T mega(T const& v) { return helper::rescaleTo1<std::mega>(v); }
template<typename T> constexpr T giga(T const& v) { return helper::rescaleTo1<std::giga>(v); }
template<typename T> constexpr T tera(T const& v) { return helper::rescaleTo1<std::tera>(v); }
template<typename T> constexpr T peta(T const& v) { return helper::rescaleTo1<std::peta>(v); }
namespace u {
using unitless = BaseUnit<-1,6>;
using meter = BaseUnit<0,6>;
using kilogram = BaseUnit<1,6>;
using second = BaseUnit<2,6>;
using ampere = BaseUnit<3,6>;
using kelvin = BaseUnit<4,6>;
using mole = BaseUnit<5,6>;
using candela = BaseUnit<6,6>;
using radian = unitless;
using steradian = unitless;
using hertz = quotient_unit< unitless, second>;
using newton = quotient_unit< product_unit<kilogram, meter>, sqare_unit<second>>;
using pascal = quotient_unit< newton, sqare_unit<meter>>;
using joule = quotient_unit< newton, meter>;
using watt = quotient_unit< joule, second>;
using coulomb = product_unit< second, ampere>;
using volt = quotient_unit< watt, ampere>;
using farad = quotient_unit< coulomb, volt>;
using ohm = quotient_unit< volt, ampere>;
using siemens = quotient_unit< ampere, volt>;
using weber = product_unit< volt, second>;
using tesla = quotient_unit< weber, sqare_unit<meter>>;
using henry = quotient_unit< weber, ampere>;
using lumen = product_unit< candela, steradian>;
using lux = quotient_unit< lumen, sqare_unit<meter>>;
using becquerel = hertz;
using gray = quotient_unit< joule, kilogram>;
using sievert = gray;
using katal = quotient_unit< mole, second>;
using meter_cubed = product_unit< meter, sqare_unit<meter>>;
using meter_per_second = quotient_unit< meter, second>;
using meter_per_second_squared = quotient_unit< meter, sqare_unit<second>>;
using mol_inv = quotient_unit< unitless, mole>;
}
namespace t {
using def = double;
using unitless = Quantity<u::unitless, def>;
using meter = Quantity<u::meter, def>;
using kilogram = Quantity<u::kilogram, def>;
using second = Quantity<u::second, def>;
using ampere = Quantity<u::ampere, def>;
using kelvin = Quantity<u::kelvin, def>;
using mole = Quantity<u::mole, def>;
using candela = Quantity<u::candela, def>;
using radian = Quantity<u::radian, def>;
using steradian = Quantity<u::steradian, def>;
using hertz = Quantity<u::hertz, def>;
using newton = Quantity<u::newton, def>;
using pascal = Quantity<u::pascal, def>;
using joule = Quantity<u::joule, def>;
using watt = Quantity<u::watt, def>;
using coulomb = Quantity<u::coulomb, def>;
using volt = Quantity<u::volt, def>;
using farad = Quantity<u::farad, def>;
using ohm = Quantity<u::ohm, def>;
using siemens = Quantity<u::siemens, def>;
using weber = Quantity<u::weber, def>;
using tesla = Quantity<u::tesla, def>;
using henry = Quantity<u::henry, def>;
using lumen = Quantity<u::lumen, def>;
using lux = Quantity<u::lux, def>;
using becquerel = Quantity<u::becquerel, def>;
using gray = Quantity<u::gray, def>;
using sievert = Quantity<u::sievert, def>;
using katal = Quantity<u::katal, def>;
using meter_cubed = Quantity<u::meter_cubed, def>;
}
constexpr t::unitless unitless{1};
constexpr t::unitless number{1};
constexpr t::meter meter{1};
constexpr t::kilogram kilogram{1};
constexpr t::second second{1};
constexpr t::ampere ampere{1};
constexpr t::kelvin kelvin{1};
constexpr t::mole mole{1};
constexpr t::candela candela{1};
constexpr t::radian radian{1};
constexpr t::steradian steradian{1};
constexpr t::hertz hertz{1};
constexpr t::newton newton{1};
constexpr t::pascal pascal{1};
constexpr t::joule joule{1};
constexpr t::watt watt{1};
constexpr t::coulomb coulomb{1};
constexpr t::volt volt{1};
constexpr t::farad farad{1};
constexpr t::ohm ohm{1};
constexpr t::siemens siemens{1};
constexpr t::weber weber{1};
constexpr t::tesla tesla{1};
constexpr t::henry henry{1};
constexpr t::lumen lumen{1};
constexpr t::lux lux{1};
constexpr t::becquerel becquerel{1};
constexpr t::gray gray{1};
constexpr t::sievert sievert{1};
constexpr t::katal katal{1};
constexpr t::meter inch{centi(2.54)};
constexpr t::meter food{0.3048};
constexpr t::meter mile{1609.344};
constexpr t::meter yard{0.9144};
constexpr t::kilogram pound{0.45359237};
constexpr t::kilogram ounce{0.02834952};
constexpr t::kilogram gram{helper::rescale<std::ratio<1>,std::kilo>(1.0)};
constexpr t::second minute{60};
constexpr t::second hour{60*60};
constexpr t::second day{60*60*24};
constexpr t::joule calorie{4.184};
constexpr t::joule watt_hour{3600};
constexpr t::meter_cubed liter{0.001};
constexpr t::meter_cubed gallon{3.785412 * 0.001};
constexpr t::pascal bar{kilo(100)};
constexpr t::unitless parts_per_million{micro(1.0)};
constexpr t::unitless percent{centi(1.0)};
constexpr t::kelvin celsius ( double v ){ return t::kelvin {static_cast<double>(v+273.15)};}
constexpr t::kelvin fahrenheit ( double v ){ return t::kelvin {static_cast<double>((v+459.67)*5.0/9.0)};}
namespace literals {
constexpr t::unitless operator"" _unitless ( long double v ) {return t::unitless {static_cast<double>(v)};}
constexpr t::unitless operator"" _number ( long double v ) {return t::unitless {static_cast<double>(v)};}
constexpr t::unitless operator"" _n ( long double v ) {return t::unitless {static_cast<double>(v)};}
constexpr t::newton operator"" _newton ( long double v ) {return t::newton {static_cast<double>(v)};}
}
template<typename U> constexpr const char* unitSymbol();
template<> inline constexpr const char* unitSymbol< u::meter>(){ return "m";}
template<> inline constexpr const char* unitSymbol<u::kilogram>(){ return "kg";}
template<> inline constexpr const char* unitSymbol< u::second>(){ return "s";}
template<> inline constexpr const char* unitSymbol< u::ampere>(){ return "A";}
template<> inline constexpr const char* unitSymbol< u::kelvin>(){ return "K";}
template<> inline constexpr const char* unitSymbol< u::mole>(){ return "mol";}
template<> inline constexpr const char* unitSymbol< u::candela>(){ return "cd";}
template<typename U> void print_unit(std::ostream& s);
template<> inline void print_unit< u::hertz>(std::ostream& s){ s<<"Hz"; }
template<> inline void print_unit< u::newton>(std::ostream& s){ s<<"N"; }
template<> inline void print_unit< u::pascal>(std::ostream& s){ s<<"Pa"; }
template<> inline void print_unit< u::joule>(std::ostream& s){ s<<"J"; }
template<> inline void print_unit< u::watt>(std::ostream& s){ s<<"W"; }
template<> inline void print_unit< u::coulomb>(std::ostream& s){ s<<"C"; }
template<> inline void print_unit< u::volt>(std::ostream& s){ s<<"V"; }
template<> inline void print_unit< u::farad>(std::ostream& s){ s<<"F"; }
template<> inline void print_unit< u::ohm>(std::ostream& s){ s<<"Ohm"; }
template<> inline void print_unit< u::siemens>(std::ostream& s){ s<<"S"; }
template<> inline void print_unit< u::weber>(std::ostream& s){ s<<"Wb"; }
template<> inline void print_unit< u::tesla>(std::ostream& s){ s<<"T"; }
template<> inline void print_unit< u::henry>(std::ostream& s){ s<<"H"; }
template<> inline void print_unit< u::lumen>(std::ostream& s){ s<<"lm"; }
template<> inline void print_unit< u::lux>(std::ostream& s){ s<<"Lx"; }
template<> inline void print_unit< u::gray>(std::ostream& s){ s<<"Gy"; }
template<> inline void print_unit< u::katal>(std::ostream& s){ s<<"ka"; }
}
int main() {
using namespace unit;
using namespace unit::literals;
t::newton some_force = 2.0_n*meter * 3.0_n*kilogram / square(2.0_n*second);
std::cout<<some_force<<"\n"; //prints "1.5N"
return 0;
}