11#ifndef _CPG_RATIONAL_HPP
12#define _CPG_RATIONAL_HPP
25#if defined(INCLUDE_PERMU_COMBI_TABLE) && !defined(PERMU_COMBI_TABLE_INCLUDED)
27 #define PERMU_COMBI_TABLE_INCLUDED
29 #if defined(PERMU_COMBI_TABLE_NAME)
30 #include PERMU_COMBI_TABLE_NAME
38 #ifdef INCLUDE_PERMU_COMBI_TABLE
49 types::type_container<float, double, long double>;
51 template<
typename Type>
56 types::type_container<char,
signed char,
57 unsigned char, short,
unsigned short,
58 int,
unsigned int, long,
unsigned long,
59 long long,
unsigned long long>;
66 types::type_container<char,
unsigned char, short,
unsigned short,
67 int,
unsigned int, long,
unsigned long,
68 long long,
unsigned long long, float, double,
long double>;
70 template<
typename Type>
76 template<allowed_type_c ElementType>
84 if constexpr(std::is_signed_v<ElementType>)
99 template<allowed_type_c ElementType>
106 A /= G;
B /= G;
return G;
108 catch(
const std::exception& e)
110 std::cerr << e.what() <<
'\n';
115 template<allowed_type_c T>
118 auto max_number = std::numeric_limits<T>::max();
120 auto lhs = (
long double)(T)1/(
long double)max_number;
121 auto rhs = (
long double)(T)1/(
long double)(max_number - 1);
126 template<allowed_type_c ElementType>
148 ElementType denominator,
bool DoNotReduce =
false) noexcept:
151 if(DoNotReduce ==
false)
157 return { this->m_num > 0 ? this->
m_num : -this->
m_num,
161 template<
typename Type = ElementType>
164 const auto& p = this->
m_num;
165 const auto& q = this->
m_den;
169 return (Type)std::round((
float) p / q);
177 template<
typename Type = ElementType>
180 const auto& p = this->m_num > 0 ? this->
m_num : -this->
m_num;
181 const auto& q = this->
m_den;
185 return (Type)std::round((
float) p / q);
197 constexpr bool valid() const noexcept
199 return (this->m_den > 0);
203 constexpr operator bool() const noexcept
205 return valid() && (this->m_num != 0);
211 return valid() && (this->m_num == 0);
215 constexpr const ElementType&
num() const noexcept
221 constexpr const ElementType&
den() const noexcept
228 constexpr ElementType
num(ElementType new_value,
bool DoNotReduce =
false) noexcept
230 auto old_value = this->
m_num;
231 this->m_num = new_value;
233 if(DoNotReduce ==
false)
241 constexpr ElementType
den(ElementType new_value,
bool DoNotReduce =
false) noexcept
243 auto old_value = this->
m_den;
244 this->m_den = new_value;
246 if(DoNotReduce ==
false)
255 (ElementType numerator, ElementType denominator,
bool DoNotReduce =
false)
noexcept
257 auto old_value = *
this;
258 this->m_num = numerator;
259 this->m_den = denominator;
261 if(DoNotReduce==
false)
268 constexpr void set(ElementType numerator,
269 ElementType denominator,
bool DoNotReduce =
false) noexcept
271 this->m_num = numerator;
272 this->m_den = denominator;
274 if(DoNotReduce==
false)
283 *
this += 1;
return *
this;
291 *
this -= 1;
return *
this;
299 auto old_value = *
this;
309 auto old_value = *
this;
314 template<number_c Type =
long long>
315 constexpr operator Type() const noexcept
317 return (Type)this->m_num / this->
m_den;
324 return (TargetType)std::round((RoundType)this->m_num / this->m_den);
328 friend constexpr std::strong_ordering
334 return std::strong_ordering::equal;
336 return std::strong_ordering::less;
338 return std::strong_ordering::greater;
342 if constexpr(tell_comparable_as_double<ElementType>())
344 long double l = lhs;
long double r = rhs;
347 return std::strong_ordering::less;
349 return std::strong_ordering::greater;
351 return std::strong_ordering::equal;
369 return std::strong_ordering::less;
371 return std::strong_ordering::greater;
373 return std::strong_ordering::equal;
379 (
const rational& lhs, ElementType rhs)
noexcept
384 friend constexpr bool operator ==
387 if( lhs.
m_den == rhs.m_den && lhs.
m_num == rhs.m_num)
393 friend constexpr bool operator ==
394 (
const rational& lhs, ElementType rhs)
noexcept
406 if constexpr(std::is_signed_v<ElementType>)
463 rhs *= lhs;
return rhs;
469 lhs *= rhs;
return lhs;
505 return {
A, P * rhs };
511 lhs *= rhs;
return lhs;
517 lhs /= rhs;
return lhs;
564 *
this =
rational{ g * Q *
A + g * P *
B, Q * P * G };
598 *
this =
rational{ g * Q *
A - g * P *
B, Q * P * G };
606 lhs += rhs;
return lhs;
612 lhs -= rhs;
return lhs;
656 rhs += lhs;
return rhs;
670 return { lhs * Q -
B, Q };
676 lhs += rhs;
return lhs;
682 lhs -= rhs;
return lhs;
685 template<
typename CharType>
687 std::basic_ostream<CharType>& os,
const rational& r)
noexcept
689 if constexpr(std::is_same_v<ElementType, char>
690 || std::is_same_v<ElementType, signed char>)
698 else if constexpr(std::is_same_v<ElementType, unsigned char> )
701 << (
unsigned short)r.m_num
703 << (
unsigned short)r.m_den
720 template<allowed_type_c L, allowed_type_c R>
721 requires ( !std::same_as<L, R>)
724 using common_t = std::common_type_t<L, R>;
732 template<allowed_type_c L, allowed_type_c R>
733 requires ( !std::same_as<L, R>)
736 using common_t = std::common_type_t<L, R>;
744 template<allowed_type_c L, real_number_c R>
747 long double l = (
long double)lhs;
748 long double r = (
long double)rhs;
751 return std::strong_ordering::less;
753 return std::strong_ordering::greater;
755 return std::strong_ordering::equal;
758 template<allowed_type_c L, allowed_type_c R>
759 requires ( !std::same_as<L, R>)
762 using common_t = std::common_type_t<L, R>;
770 template<allowed_type_c L, allowed_type_c R>
771 requires ( !std::same_as<L, R>)
774 using common_t = std::common_type_t<L, R>;
782 template<allowed_type_c L, real_number_c R>
785 long double l = (
long double)lhs;
786 long double r = (
long double)rhs;
788 long double diff = abs(l - r);
790 constexpr auto epsilon =
791 std::numeric_limits<R>::epsilon();
793 return (diff < epsilon);
796 #ifdef INCLUDE_PERMU_COMBI_TABLE
798 auto factorial(
unsigned long long n)
noexcept
800 std::optional<unsigned long long> result;
809 auto nPr(
unsigned long long n,
unsigned long long r)
noexcept
811 std::optional<unsigned long long> result;
815 result = 1;
return result;
819 result = n;
return result;
830 unsigned long long old_value = 0;
831 unsigned long long new_value = 1;
835 for(
unsigned long long k = 0; k < r; ++k )
837 old_value = new_value;
840 if(old_value != new_value /(n-k))
842 success =
false;
break;
846 if(success) result = new_value;
853 auto nCr(
unsigned long long n,
unsigned long long r)
noexcept
855 std::optional<unsigned long long> result;
859 result = 1;
return result;
862 if ( r > (n-r) ) r = n-r;
866 if ( r > (n-r) ) r = n-r;
883 rational<unsigned long long> old_value;
884 rational<unsigned long long> new_value{1};
888 for(
unsigned long long k = 0; k < r; ++k)
890 auto value = rational<unsigned long long>{n - k, r - k};
892 old_value = new_value;
895 if(old_value != (new_value / value))
897 success =
false;
break;
902 result = (
unsigned long long)new_value;
911 std::optional<unsigned long long> result;
913 unsigned long long old_value;
914 unsigned long long new_value = 1;
917 for(
unsigned long long k = 1; k <= n; ++k)
919 old_value = new_value; new_value *= k;
921 if(old_value != new_value / k)
923 success =
false;
break;
927 if(success) result = new_value;
933 auto nPr(
unsigned long long n,
unsigned long long r = 1) noexcept
935 std::optional<unsigned long long> result;
937 unsigned long long old_value;
938 unsigned long long new_value = 1;
941 for(
unsigned long long k = 0; k < r; ++k)
943 old_value = new_value;
946 if(old_value != (new_value / (n-k)))
948 success =
false;
break;
952 if(success) result = new_value;
958 auto nCr(
unsigned long long n,
unsigned long long r)
noexcept
969 std::optional<unsigned long long> result;
973 result = 1;
return result;
976 if ( r > (n-r) ) r = n-r;
983 for(
unsigned long long k = 0; k < r; ++k)
987 old_value = new_value;
990 if(old_value != (new_value / value))
992 success =
false;
break;
997 result = (
unsigned long long)new_value;
constexpr rational reciprocal() const noexcept
constexpr rational abs() const noexcept
constexpr rational operator++(int) noexcept
constexpr bool operator!() const noexcept
friend constexpr rational operator-(rational lhs, const rational &rhs) noexcept
constexpr rational & operator*=(const rational &rhs) noexcept
friend constexpr rational operator/(const rational &lhs, ElementType rhs) noexcept
friend constexpr rational operator*(rational lhs, ElementType rhs) noexcept
friend constexpr std::strong_ordering operator<=>(const rational &lhs, const rational &rhs)
friend constexpr rational operator*(rational lhs, const rational &rhs) noexcept
Type mag() const noexcept
constexpr rational(ElementType numerator, ElementType denominator, bool DoNotReduce=false) noexcept
friend constexpr rational operator+(rational lhs, const rational &rhs) noexcept
constexpr rational operator--(int) noexcept
friend constexpr rational operator/(rational lhs, const rational &rhs) noexcept
constexpr rational & operator-=(const rational &rhs) noexcept
friend std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &os, const rational &r) noexcept
friend constexpr rational operator*(ElementType lhs, rational rhs) noexcept
constexpr rational inverse() const noexcept
constexpr const rational & operator++() noexcept
friend constexpr rational operator/(ElementType lhs, const rational &rhs) noexcept
constexpr void set(ElementType numerator, ElementType denominator, bool DoNotReduce=false) noexcept
constexpr const rational & operator--() noexcept
TargetType round() const noexcept
constexpr const ElementType & num() const noexcept
constexpr bool valid() const noexcept
constexpr rational & operator/=(const rational &rhs) noexcept
constexpr ElementType num(ElementType new_value, bool DoNotReduce=false) noexcept
constexpr ElementType den(ElementType new_value, bool DoNotReduce=false) noexcept
constexpr const ElementType & den() const noexcept
constexpr rational() noexcept=default
constexpr rational & operator+=(const rational &rhs) noexcept
constexpr void reduce() noexcept
constexpr rational operator-() const noexcept
Type abs_mag() const noexcept
friend constexpr rational operator+(rational lhs, ElementType rhs) noexcept
#define Cpg_CharStr(asciistr)
std::common_type_t< S, T > common_t
types::type_container< char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long > allowed_type_list
types::type_container< float, double, long double > real_number_list
constexpr bool tell_comparable_as_double()
constexpr ElementType reduce_simple(ElementType &A, ElementType &B) noexcept
std::strong_ordering operator<=>(rational< L > const &lhs, rational< R > const &rhs)
const std::vector< std::vector< unsigned long long > > permutation_table
const std::vector< unsigned long long > factorial_table
const std::vector< std::vector< unsigned long long > > combination_table
auto factorial(unsigned long long n) noexcept
types::type_container< char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double > numerical_type_list
auto nCr(unsigned long long n, unsigned long long r) noexcept
constexpr ElementType reduce_adjusted(ElementType &A, ElementType &B) noexcept
auto nPr(unsigned long long n, unsigned long long r=1) noexcept
bool operator==(rational< L > const &lhs, rational< R > const &rhs)
enable_if_in_list_t< Type, integral_list_t > gcd(Type a, Type b)
Type to string name conversions are defined.