10 #if !defined(CNL_IMPL_SCALED_INTEGER_MATH_H)
11 #define CNL_IMPL_SCALED_INTEGER_MATH_H
13 #include "definition.h"
26 template<
class ScaledInteger>
27 [[nodiscard]] constexpr
auto rounding_conversion(
double d)
30 set_digits_t<rep_of_t<ScaledInteger>, digits_v<ScaledInteger> + 1>,
32 return from_rep<ScaledInteger>(
33 static_cast<rep_of_t<ScaledInteger>
>((_impl::to_rep(one_longer{d}) + 1) >> 1));
36 template<
class ScaledInteger>
40 using make_largest_ufraction =
41 scaled_integer<unsigned_rep<Input>, power<-digits_v<unsigned_rep<Input>>>>;
53 template<
class CoeffType>
55 static constexpr CoeffType a1{rounding_conversion<CoeffType>(0.6931471860838825)};
56 static constexpr CoeffType a2{rounding_conversion<CoeffType>(0.2402263846181129)};
57 static constexpr CoeffType a3{rounding_conversion<CoeffType>(0.055505126858894846)};
58 static constexpr CoeffType a4{rounding_conversion<CoeffType>(0.009614017013719252)};
59 static constexpr CoeffType a5{
60 rounding_conversion<CoeffType>(0.0013422634797558564)};
61 static constexpr CoeffType a6{
62 rounding_conversion<CoeffType>(0.00014352314226313836)};
63 static constexpr CoeffType a7{
64 rounding_conversion<CoeffType>(0.000021498763160402416)};
67 template<
typename A,
typename B>
68 [[nodiscard]] constexpr
auto safe_multiply(A
const& a, B
const& b) requires(
digits_v<decltype(a * b)> <= digits_v<A> + digits_v<B>)
70 return set_digits_t<A, digits_v<A> + digits_v<B>>{a}
71 * set_digits_t<B, digits_v<A> + digits_v<B>>{b};
74 template<
typename A,
typename B>
75 [[nodiscard]] constexpr
auto safe_multiply(A
const& a, B
const& b) requires(digits_v<A> + digits_v<B> <=
digits_v<decltype(a * b)>)
80 template<
class Rep,
int Exponent>
81 [[nodiscard]]
inline constexpr
auto evaluate_polynomial(
84 using fp = scaled_integer<Rep, power<Exponent>>;
89 using coeffs = poly_coeffs<fp>;
90 return fp{safe_multiply(
110 xf)}))}))}))}))}))}))};
116 template<
class Rep,
int Exponent>
117 [[nodiscard]]
inline constexpr
auto exp2m1_0to1(
scaled_integer<Rep, power<Exponent>>) requires(Exponent >= 0)
120 return from_rep<make_largest_ufraction<scaled_integer<Rep, power<Exponent>>>>(0);
124 template<
class Rep,
int Exponent>
125 [[nodiscard]]
inline constexpr
auto exp2m1_0to1(
scaled_integer<Rep, power<Exponent>> x) requires(Exponent < 0)
130 using im = make_largest_ufraction<scaled_integer<Rep, power<Exponent>>>;
133 return evaluate_polynomial(im{scaled_integer<rep_of_t<im>, power<Exponent>>{x}});
136 template<
class Rep,
int Exponent,
int Radix>
137 requires(-digits_v<Rep> < Exponent)
138 [[nodiscard]] constexpr
auto fractional(
145 template<
class Rep,
int Exponent,
int Radix>
146 requires(-digits_v<Rep> >= Exponent)
147 [[nodiscard]] constexpr
auto fractional(
scaled_integer<Rep, power<Exponent, Radix>>
const& x, Rep
const&)
152 template<
class Intermediate,
typename Rep,
int Exponent>
153 [[nodiscard]] constexpr
auto exp2(
154 scaled_integer<Rep, power<Exponent>>
const& x, Rep
const& floored)
156 return floored <= Exponent
157 ? rep_of_t<Intermediate>{1}
161 : (_impl::to_rep(exp2m1_0to1<Rep, Exponent>(fractional(
164 >> (-tag_of_t<Intermediate>::exponent + Exponent
182 template<
class Rep,
int Exponent>
183 [[nodiscard]] constexpr
auto
188 using im = _impl::fp::make_largest_ufraction<out_type>;
192 return _impl::from_rep<out_type>(_impl::fp::exp2<im>(x,
static_cast<Rep
>(floor(x))));