#pragma once #include #include #include #include namespace hpr { // type traits template struct is_scalar : public std::is_floating_point {}; // concepts template concept IsScalar = is_scalar::value; template concept IsReal = is_integer::value || is_scalar::value; // forward declaration template class Scalar; } namespace std { template struct is_floating_point> : true_type {}; } namespace hpr { // class declaration template class Scalar { public: using type = Scalar; using value_type = T; protected: value_type p_value; public: // constructors constexpr Scalar() : p_value {} {} template constexpr Scalar(const Scalar& value) : p_value {static_cast(value.p_value)} {} template constexpr Scalar(const X& value) : p_value {static_cast(value)} {} template constexpr type& operator=(const Scalar& value) { p_value = static_cast(value.p_value); return *this; } template constexpr type& operator=(const X& value) { p_value = static_cast(value); return *this; } virtual constexpr ~Scalar() = default; // conversion constexpr operator double() const { return static_cast(p_value); } constexpr operator float() const { return static_cast(p_value); } constexpr operator long double() const { return static_cast(p_value); } constexpr operator bool() const { return static_cast(p_value); } // access [[nodiscard]] constexpr value_type value() const { return p_value; } constexpr value_type& value() { return p_value; } // properties /*protected: static value_type s_precision; public: static constexpr Scalar precision() { return s_precision; } static constexpr void precision(const value_type& precision) { s_precision = precision; } static constexpr Scalar inf() { return std::numeric_limits::infinity(); } static constexpr Scalar epsilon() { return std::numeric_limits::epsilon(); }*/ }; // specialization type #if defined(HPR_SCALAR_IMPLEMENTAION) #if defined(HPR_SCALAR_LONGDOUBLE) using scalar_type = long double; using scalar = Scalar; #elif defined(HPR_SCALAR_DOUBLE) using scalar_type = double; using scalar = Scalar; #elif defined(HPR_SCALAR_FLOAT) using scalar_type = float; using scalar = Scalar; #else using scalar_type = double; using scalar = Scalar; #endif #else #if defined(HPR_SCALAR_LONGDOUBLE) using scalar_type = long double; using scalar = long double; #elif defined(HPR_SCALAR_DOUBLE) using scalar_type = double; using scalar = double; #elif defined(HPR_SCALAR_FLOAT) using scalar_type = float; using scalar = float; #else using scalar_type = float; using scalar = float; #endif #endif // #if defined(HPR_SCALAR_IMPLEMENTATION) template<> scalar::value_type scalar::s_precision = static_cast(1e-15); // global operators /// scalar vs scalar constexpr scalar operator+(const scalar& s) { return s; } constexpr scalar operator-(const scalar& s) { return -s.value(); } constexpr bool operator!(const scalar& s) { return !static_cast(s.value()); } constexpr scalar& operator+=(scalar& lhs, const scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } constexpr scalar& operator-=(scalar& lhs, const scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } constexpr scalar& operator*=(scalar& lhs, const scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } constexpr scalar& operator/=(scalar& lhs, const scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } constexpr scalar operator+(const scalar& lhs, const scalar& rhs) { return lhs.value() + rhs.value(); } constexpr scalar operator-(const scalar& lhs, const scalar& rhs) { return lhs.value() - rhs.value(); } constexpr scalar operator*(const scalar& lhs, const scalar& rhs) { return lhs.value() * rhs.value(); } constexpr scalar operator/(const scalar& lhs, const scalar& rhs) { return lhs.value() / rhs.value(); } constexpr bool operator==(const scalar& lhs, const scalar& rhs) { return lhs.value() == rhs.value(); } constexpr bool operator!=(const scalar& lhs, const scalar& rhs) { return lhs.value() != rhs.value(); } constexpr bool operator&&(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } constexpr bool operator||(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } constexpr bool operator>(const scalar& lhs, const scalar& rhs) { return lhs.value() > rhs.value(); } constexpr bool operator<(const scalar& lhs, const scalar& rhs) { return lhs.value() < rhs.value(); } constexpr bool operator>=(const scalar& lhs, const scalar& rhs) { return lhs.value() >= rhs.value(); } constexpr bool operator<=(const scalar& lhs, const scalar& rhs) { return lhs.value() <= rhs.value(); } //std::ostream& operator<<(std::ostream& stream, const scalar& s) { return stream << s.value(); } /// scalar vs Scalar template constexpr scalar& operator+=(scalar& lhs, const Scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } template constexpr scalar& operator-=(scalar& lhs, const Scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } template constexpr scalar& operator*=(scalar& lhs, const Scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } template constexpr scalar& operator/=(scalar& lhs, const Scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } template constexpr scalar operator+(const scalar& lhs, const Scalar& rhs) { return lhs.value() + static_cast(rhs.value()); } template constexpr scalar operator+(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) + rhs.value(); } template constexpr scalar operator-(const scalar& lhs, const Scalar& rhs) { return lhs.value() - static_cast(rhs.value()); } template constexpr scalar operator-(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) - rhs.value(); } template constexpr scalar operator*(const scalar& lhs, const Scalar& rhs) { return lhs.value() * static_cast(rhs.value()); } template constexpr scalar operator*(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) * rhs.value(); } template constexpr scalar operator/(const scalar& lhs, const Scalar& rhs) { return lhs.value() / static_cast(rhs.value()); } template constexpr scalar operator/(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) / rhs.value(); } template constexpr bool operator==(const scalar& lhs, const Scalar& rhs) { return lhs.value() == static_cast(rhs.value()); } template constexpr bool operator==(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) == rhs.value(); } template constexpr bool operator!=(const scalar& lhs, const Scalar& rhs) { return lhs.value() != static_cast(rhs.value()); } template constexpr bool operator!=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) != rhs.value(); } template constexpr bool operator&&(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator&&(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator||(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator||(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator>(const scalar& lhs, const Scalar& rhs) { return lhs.value() > static_cast(rhs.value()); } template constexpr bool operator>(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) > rhs.value(); } template constexpr bool operator<(const scalar& lhs, const Scalar& rhs) { return lhs.value() < static_cast(rhs.value()); } template constexpr bool operator<(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) < rhs.value(); } template constexpr bool operator>=(const scalar& lhs, const Scalar& rhs) { return lhs.value() >= static_cast(rhs.value()); } template constexpr bool operator>=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) >= rhs.value(); } template constexpr bool operator<=(const scalar& lhs, const Scalar& rhs) { return lhs.value() <= static_cast(rhs.value()); } template constexpr bool operator<=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) <= rhs.value(); } template std::ostream& operator<<(std::ostream& stream, const Scalar& s) { return stream << s.value(); } template std::istream& operator>>(std::istream& stream, Scalar& s) { return stream >> s.value(); } /// scalar vs real template constexpr scalar& operator+=(scalar& lhs, const T& rhs) { lhs.value() += static_cast(rhs); return lhs; } template constexpr scalar& operator-=(scalar& lhs, const T& rhs) { lhs.value() -= static_cast(rhs); return lhs; } template constexpr scalar& operator*=(scalar& lhs, const T& rhs) { lhs.value() *= static_cast(rhs); return lhs; } template constexpr scalar& operator/=(scalar& lhs, const T& rhs) { lhs.value() /= static_cast(rhs); return lhs; } template constexpr T& operator+=(T& lhs, const scalar& rhs) { lhs += static_cast(rhs); return lhs; } template constexpr T& operator-=(T& lhs, const scalar& rhs) { lhs -= static_cast(rhs); return lhs; } template constexpr T& operator*=(T& lhs, const scalar& rhs) { lhs *= static_cast(rhs); return lhs; } template constexpr T& operator/=(T& lhs, const scalar& rhs) { lhs /= static_cast(rhs); return lhs; } template constexpr scalar operator+(const scalar& lhs, const T& rhs) { return lhs.value() + static_cast(rhs); } template constexpr scalar operator+(const T& lhs, const scalar& rhs) { return static_cast(lhs) + rhs.value(); } template constexpr scalar operator-(const scalar& lhs, const T& rhs) { return lhs.value() - static_cast(rhs); } template constexpr scalar operator-(const T& lhs, const scalar& rhs) { return static_cast(lhs) - rhs.value(); } template constexpr scalar operator*(const scalar& lhs, const T& rhs) { return lhs.value() * static_cast(rhs); } template constexpr scalar operator*(const T& lhs, const scalar& rhs) { return static_cast(lhs) * rhs.value(); } template constexpr scalar operator/(const scalar& lhs, const T& rhs) { return lhs.value() / static_cast(rhs); } template constexpr scalar operator/(const T& lhs, const scalar& rhs) { return static_cast(lhs) / rhs.value(); } template constexpr bool operator==(const scalar& lhs, const T& rhs) { return lhs.value() == static_cast(rhs); } template constexpr bool operator==(const T& lhs, const scalar& rhs) { return static_cast(lhs) == rhs.value(); } template constexpr bool operator!=(const scalar& lhs, const T& rhs) { return lhs.value() != static_cast(rhs); } template constexpr bool operator!=(const T& lhs, const scalar& rhs) { return static_cast(lhs) != rhs.value(); } template constexpr bool operator&&(const scalar& lhs, const T& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator&&(const T& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } template constexpr bool operator||(const scalar& lhs, const T& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator||(const T& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } template constexpr bool operator>(const scalar& lhs, const T& rhs) { return lhs.value() > static_cast(rhs); } template constexpr bool operator>(const T& lhs, const scalar& rhs) { return static_cast(lhs) > rhs.value(); } template constexpr bool operator<(const scalar& lhs, const T& rhs) { return lhs.value() < static_cast(rhs); } template constexpr bool operator<(const T& lhs, const scalar& rhs) { return static_cast(lhs) < rhs.value(); } template constexpr bool operator>=(const scalar& lhs, const T& rhs) { return lhs.value() >= static_cast(rhs); } template constexpr bool operator>=(const T& lhs, const scalar& rhs) { return static_cast(lhs) >= rhs.value(); } template constexpr bool operator<=(const scalar& lhs, const T& rhs) { return lhs.value() <= static_cast(rhs); } template constexpr bool operator<=(const T& lhs, const scalar& rhs) { return static_cast(lhs) <= rhs.value(); } #endif // transcendentals template constexpr scalar cos(const T& s) { return std::cos(static_cast(s));} template constexpr scalar acos(const T& s) { return std::acos(static_cast(s)); } template constexpr scalar cosh(const T& s) { return std::cosh(static_cast(s)); } template constexpr scalar acosh(const T& s) { return std::acosh(static_cast(s)); } template constexpr scalar sin(const T& s) { return std::sin(static_cast(s)); } template constexpr scalar asin(const T& s) { return std::asin(static_cast(s)); } template constexpr scalar sinh(const T& s) { return std::sinh(static_cast(s)); } template constexpr scalar asinh(const T& s) { return std::asinh(static_cast(s)); } template constexpr scalar tan(const T& s) { return std::tan(static_cast(s)); } template constexpr scalar atan(const T& s) { return std::atan(static_cast(s)); } template constexpr scalar atan2(const T& s, const X& s2) { return std::atan2(static_cast(s), static_cast(s2)); } template constexpr scalar tanh(const T& s) { return std::tanh(static_cast(s)); } template constexpr scalar atanh(const T& s) { return std::atanh(static_cast(s)); } template constexpr scalar exp(const T& s) { return std::exp(static_cast(s)); } template constexpr scalar log(const T& s) { return std::log(static_cast(s)); } template constexpr scalar log10(const T& s) { return std::log10(static_cast(s)); } template constexpr scalar pow(const T& s, const X& d) { return std::pow(static_cast(s), static_cast(d)); } template constexpr scalar sqrt(const T& s) { return std::sqrt(static_cast(s)); } template constexpr scalar isqrt(const T& s) { return static_cast(1) / sqrt(static_cast(s)); } // constants constexpr scalar pi() { return std::numbers::pi_v; } constexpr scalar e() { return std::numbers::e_v; } // etc static float _scalar_float_precision = 1e-15f; static double _scalar_double_precision = 1e-15; static long double _scalar_long_double_precision = 1e-15l; template inline void precision(const T& precision) { if constexpr (std::is_same::value) _scalar_float_precision = precision; else if constexpr (std::is_same::value) _scalar_double_precision = precision; else if constexpr (std::is_same::value) _scalar_long_double_precision = precision; } template inline T precision() { if constexpr (std::is_same::value) return _scalar_float_precision; else if constexpr (std::is_same::value) return _scalar_double_precision; else if constexpr (std::is_same::value) return _scalar_long_double_precision; } constexpr scalar inf() { return std::numeric_limits::infinity(); } constexpr scalar epsilon() { return std::numeric_limits::epsilon(); } constexpr scalar isnan(const scalar& s) { return std::isnan(static_cast(s)); } constexpr scalar abs(const scalar& s) { return std::abs(static_cast(s)); } constexpr scalar mag(const scalar& s) { return std::abs(static_cast(s)); } constexpr bool equal(const scalar& lhs, const scalar& rhs, const scalar& precision = hpr::precision()) { return abs(lhs - rhs) < precision; } //! Convert degrees to radians constexpr scalar rad(const scalar& s) { return s * pi() / static_cast(180); } //! Convert radians to degrees constexpr scalar deg(const scalar& s) { return s * static_cast(180) / pi(); } constexpr scalar min(const scalar& s1, const scalar& s2) { return std::min(static_cast(s1), static_cast(s2));} constexpr scalar max(const scalar& s1, const scalar& s2) { return std::max(static_cast(s1), static_cast(s2)); } constexpr scalar clip(const scalar& s, const scalar& sMin, const scalar& sMax) { return min(sMax, max(s, sMin)); } } /*namespace std { // compatibility with std template constexpr hpr::Scalar cos(const hpr::Scalar& s) { return hpr::cos(s); } template constexpr hpr::Scalar acos(const hpr::Scalar& s) { return hpr::acos(s); } template constexpr hpr::Scalar cosh(const hpr::Scalar& s) { return hpr::cosh(s); } template constexpr hpr::Scalar acosh(const hpr::Scalar& s) { return hpr::acosh(s); } template constexpr hpr::Scalar sin(const hpr::Scalar& s) { return hpr::sin(s); } template constexpr hpr::Scalar asin(const hpr::Scalar& s) { return hpr::asin(s); } template constexpr hpr::Scalar sinh(const hpr::Scalar& s) { return hpr::sinh(s); } template constexpr hpr::Scalar asinh(const hpr::Scalar& s) { return hpr::asinh(s); } template constexpr hpr::Scalar tan(const hpr::Scalar& s) { return hpr::tan(s); } template constexpr hpr::Scalar atan(const hpr::Scalar& s) { return hpr::atan(s); } template constexpr hpr::Scalar tanh(const hpr::Scalar& s) { return hpr::tanh(s); } template constexpr hpr::Scalar atanh(const hpr::Scalar& s) { return hpr::atanh(s); } template constexpr hpr::Scalar exp(const hpr::Scalar& s) { return hpr::exp(s); } template constexpr hpr::Scalar log(const hpr::Scalar& s) { return hpr::log(s); } template constexpr hpr::Scalar log10(const hpr::Scalar& s) { return hpr::log10(s); } template constexpr hpr::Scalar sqrt(const hpr::Scalar& s) { return hpr::sqrt(s); } template constexpr hpr::Scalar abs(const hpr::Scalar& s) { return hpr::abs(s); } template constexpr hpr::Scalar pow(const hpr::Scalar& s, const hpr::Scalar& d) { return hpr::pow(s, d); } template constexpr hpr::Scalar pow(const hpr::Scalar& s, const X& d) { return hpr::pow(s, d); } template constexpr hpr::Scalar pow(const T& s, const hpr::Scalar& d) { return hpr::pow(s, d); } }*/